lean_cms 0.2.12
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 +235 -0
- data/LICENSE +21 -0
- data/README.md +107 -0
- data/app/assets/images/lean_cms/sloth-404.png +0 -0
- data/app/assets/images/lean_cms/sloth-500.png +0 -0
- data/app/assets/images/lean_cms/sloth-favicon-16.png +0 -0
- data/app/assets/images/lean_cms/sloth-favicon-32.png +0 -0
- data/app/assets/images/lean_cms/sloth-favicon-64.png +0 -0
- data/app/assets/images/lean_cms/sloth-logo.png +0 -0
- data/app/assets/lean_cms/actiontext.css +440 -0
- data/app/assets/lean_cms/cms_edit_controls.css +548 -0
- data/app/assets/tailwind/lean_cms/engine.css +14 -0
- data/app/components/lean_cms/base_component.rb +61 -0
- data/app/components/lean_cms/bullets_section_component.html.erb +23 -0
- data/app/components/lean_cms/bullets_section_component.rb +54 -0
- data/app/components/lean_cms/cards_section_component.html.erb +237 -0
- data/app/components/lean_cms/cards_section_component.rb +71 -0
- data/app/components/lean_cms/editable_content_component.html.erb +15 -0
- data/app/components/lean_cms/editable_content_component.rb +53 -0
- data/app/components/lean_cms/section_component.html.erb +18 -0
- data/app/components/lean_cms/section_component.rb +35 -0
- data/app/controllers/concerns/lean_cms/authentication.rb +60 -0
- data/app/controllers/concerns/lean_cms/authorization.rb +60 -0
- data/app/controllers/lean_cms/activity_controller.rb +16 -0
- data/app/controllers/lean_cms/application_controller.rb +48 -0
- data/app/controllers/lean_cms/dashboard_controller.rb +13 -0
- data/app/controllers/lean_cms/form_submissions_controller.rb +37 -0
- data/app/controllers/lean_cms/notification_settings_controller.rb +145 -0
- data/app/controllers/lean_cms/notifications_controller.rb +26 -0
- data/app/controllers/lean_cms/page_contents_controller.rb +403 -0
- data/app/controllers/lean_cms/password_setup_controller.rb +65 -0
- data/app/controllers/lean_cms/passwords_controller.rb +42 -0
- data/app/controllers/lean_cms/posts_controller.rb +78 -0
- data/app/controllers/lean_cms/sessions_controller.rb +50 -0
- data/app/controllers/lean_cms/settings_controller.rb +124 -0
- data/app/controllers/lean_cms/users_controller.rb +113 -0
- data/app/helpers/lean_cms/activity_helper.rb +190 -0
- data/app/helpers/lean_cms/application_helper.rb +43 -0
- data/app/helpers/lean_cms/content_helper.rb +34 -0
- data/app/helpers/lean_cms/page_content_helper.rb +359 -0
- data/app/javascript/controllers/cards_editor_controller.js +317 -0
- data/app/javascript/controllers/cms_sticky_overlay_controller.js +59 -0
- data/app/javascript/controllers/field_editor_form_controller.js +68 -0
- data/app/javascript/controllers/field_editor_modal_controller.js +79 -0
- data/app/javascript/controllers/inline_edit_controller.js +414 -0
- data/app/javascript/controllers/inline_edit_toggle_controller.js +81 -0
- data/app/javascript/controllers/notifications_controller.js +19 -0
- data/app/javascript/controllers/settings_inline_edit_sync_controller.js +38 -0
- data/app/javascript/controllers/settings_override_controller.js +45 -0
- data/app/mailers/lean_cms/application_mailer.rb +6 -0
- data/app/mailers/lean_cms/passwords_mailer.rb +8 -0
- data/app/mailers/lean_cms/users_mailer.rb +39 -0
- data/app/models/lean_cms/current.rb +6 -0
- data/app/models/lean_cms/form_submission.rb +45 -0
- data/app/models/lean_cms/magic_link.rb +76 -0
- data/app/models/lean_cms/meta_tag.rb +30 -0
- data/app/models/lean_cms/notification_setting.rb +69 -0
- data/app/models/lean_cms/page.rb +23 -0
- data/app/models/lean_cms/page_content.rb +245 -0
- data/app/models/lean_cms/post.rb +65 -0
- data/app/models/lean_cms/session.rb +7 -0
- data/app/models/lean_cms/setting.rb +156 -0
- data/app/policies/lean_cms/application_policy.rb +35 -0
- data/app/policies/lean_cms/page_content_policy.rb +31 -0
- data/app/policies/lean_cms/post_policy.rb +37 -0
- data/app/policies/lean_cms/setting_policy.rb +17 -0
- data/app/views/layouts/lean_cms/application.html.erb +114 -0
- data/app/views/layouts/lean_cms/auth.html.erb +200 -0
- data/app/views/lean_cms/activity/index.html.erb +79 -0
- data/app/views/lean_cms/dashboard/index.html.erb +180 -0
- data/app/views/lean_cms/form_submissions/index.html.erb +104 -0
- data/app/views/lean_cms/form_submissions/show.html.erb +157 -0
- data/app/views/lean_cms/notification_settings/edit.html.erb +192 -0
- data/app/views/lean_cms/notifications/index.html.erb +72 -0
- data/app/views/lean_cms/notifications/show.html.erb +39 -0
- data/app/views/lean_cms/page_contents/_field_editor.html.erb +174 -0
- data/app/views/lean_cms/page_contents/edit.html.erb +428 -0
- data/app/views/lean_cms/page_contents/index.html.erb +113 -0
- data/app/views/lean_cms/password_setup/show.html.erb +35 -0
- data/app/views/lean_cms/passwords/edit.html.erb +26 -0
- data/app/views/lean_cms/passwords/new.html.erb +21 -0
- data/app/views/lean_cms/passwords_mailer/reset.html.erb +6 -0
- data/app/views/lean_cms/passwords_mailer/reset.text.erb +4 -0
- data/app/views/lean_cms/posts/_form.html.erb +118 -0
- data/app/views/lean_cms/posts/edit.html.erb +31 -0
- data/app/views/lean_cms/posts/index.html.erb +100 -0
- data/app/views/lean_cms/posts/new.html.erb +16 -0
- data/app/views/lean_cms/sessions/new.html.erb +28 -0
- data/app/views/lean_cms/settings/edit.html.erb +384 -0
- data/app/views/lean_cms/shared/_admin_bar.html.erb +85 -0
- data/app/views/lean_cms/shared/_header.html.erb +86 -0
- data/app/views/lean_cms/shared/_notifications_bell.html.erb +84 -0
- data/app/views/lean_cms/shared/_sidebar.html.erb +102 -0
- data/app/views/lean_cms/users/_form.html.erb +105 -0
- data/app/views/lean_cms/users/edit.html.erb +8 -0
- data/app/views/lean_cms/users/index.html.erb +99 -0
- data/app/views/lean_cms/users/new.html.erb +8 -0
- data/app/views/lean_cms/users_mailer/admin_triggered_password_reset.html.erb +13 -0
- data/app/views/lean_cms/users_mailer/admin_triggered_password_reset.text.erb +11 -0
- data/app/views/lean_cms/users_mailer/invitation.html.erb +13 -0
- data/app/views/lean_cms/users_mailer/invitation.text.erb +11 -0
- data/app/views/lean_cms/users_mailer/reactivation.html.erb +13 -0
- data/app/views/lean_cms/users_mailer/reactivation.text.erb +11 -0
- data/config/importmap.rb +8 -0
- data/config/routes.rb +78 -0
- data/db/migrate/20251112034030_create_lean_cms_tables.rb +131 -0
- data/db/migrate/20260513000001_create_lean_cms_auth_tables.rb +31 -0
- data/db/migrate/20260514000001_create_paper_trail_versions.rb +16 -0
- data/db/migrate/20260514000002_create_action_text_tables.rb +18 -0
- data/db/migrate/20260514000003_create_active_storage_tables.rb +45 -0
- data/db/migrate/20260514000004_create_noticed_tables.rb +27 -0
- data/lib/generators/lean_cms/demo/demo_generator.rb +54 -0
- data/lib/generators/lean_cms/demo/templates/lean_cms_structure.yml +129 -0
- data/lib/generators/lean_cms/demo/templates/pages_controller.rb +30 -0
- data/lib/generators/lean_cms/demo/templates/views/pages/about.html.erb +40 -0
- data/lib/generators/lean_cms/demo/templates/views/pages/contact.html.erb +55 -0
- data/lib/generators/lean_cms/demo/templates/views/pages/home.html.erb +31 -0
- data/lib/generators/lean_cms/install/install_generator.rb +317 -0
- data/lib/generators/lean_cms/install/templates/add_lean_cms_columns_to_users.rb.tt +7 -0
- data/lib/generators/lean_cms/install/templates/lean_cms.rb +11 -0
- data/lib/generators/lean_cms/install/templates/lean_cms_structure.yml +29 -0
- data/lib/lean_cms/configuration.rb +32 -0
- data/lib/lean_cms/engine.rb +93 -0
- data/lib/lean_cms/loader.rb +217 -0
- data/lib/lean_cms/sync_helper.rb +182 -0
- data/lib/lean_cms/version.rb +3 -0
- data/lib/lean_cms.rb +26 -0
- data/lib/tasks/lean_cms.rake +390 -0
- metadata +313 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<%= form_with(model: @post, url: @post.new_record? ? lean_cms_posts_path : lean_cms_post_path(@post), local: true, class: "space-y-6") do |f| %>
|
|
2
|
+
<% if @post.errors.any? %>
|
|
3
|
+
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
|
|
4
|
+
<div class="flex items-start">
|
|
5
|
+
<svg class="w-5 h-5 text-red-600 mt-0.5 mr-3 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
|
6
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
|
|
7
|
+
</svg>
|
|
8
|
+
<div>
|
|
9
|
+
<h3 class="text-sm font-medium text-red-800 mb-2">
|
|
10
|
+
<%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:
|
|
11
|
+
</h3>
|
|
12
|
+
<ul class="list-disc list-inside text-sm text-red-700 space-y-1">
|
|
13
|
+
<% @post.errors.full_messages.each do |message| %>
|
|
14
|
+
<li><%= message %></li>
|
|
15
|
+
<% end %>
|
|
16
|
+
</ul>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<% end %>
|
|
21
|
+
|
|
22
|
+
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
23
|
+
<h2 class="text-lg font-semibold text-gray-900 mb-6">Post Details</h2>
|
|
24
|
+
|
|
25
|
+
<div class="space-y-6">
|
|
26
|
+
<!-- Content Type -->
|
|
27
|
+
<div>
|
|
28
|
+
<%= f.label :content_type, "Post Type", class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
29
|
+
<div class="flex space-x-4">
|
|
30
|
+
<label class="flex items-center">
|
|
31
|
+
<%= f.radio_button :content_type, "blog", class: "w-4 h-4 text-blue-600 border-gray-300 focus:ring-blue-500" %>
|
|
32
|
+
<span class="ml-2 text-sm text-gray-700">Blog Post</span>
|
|
33
|
+
</label>
|
|
34
|
+
<label class="flex items-center">
|
|
35
|
+
<%= f.radio_button :content_type, "portfolio", class: "w-4 h-4 text-blue-600 border-gray-300 focus:ring-blue-500" %>
|
|
36
|
+
<span class="ml-2 text-sm text-gray-700">Portfolio Item</span>
|
|
37
|
+
</label>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<!-- Title -->
|
|
42
|
+
<div>
|
|
43
|
+
<%= f.label :title, class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
44
|
+
<%= f.text_field :title, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-blue-600 focus:outline-solid", placeholder: "Enter post title" %>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<!-- Slug -->
|
|
48
|
+
<div>
|
|
49
|
+
<%= f.label :slug, class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
50
|
+
<div class="flex items-center">
|
|
51
|
+
<span class="text-sm text-gray-500 mr-2">/blog/</span>
|
|
52
|
+
<%= f.text_field :slug, class: "flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-blue-600 focus:outline-solid", placeholder: "post-slug" %>
|
|
53
|
+
</div>
|
|
54
|
+
<p class="text-xs text-gray-500 mt-1">URL-friendly version of the title. Leave blank to auto-generate.</p>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- Excerpt -->
|
|
58
|
+
<div>
|
|
59
|
+
<%= f.label :excerpt, class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
60
|
+
<%= f.text_area :excerpt, rows: 3, class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-blue-600 focus:outline-solid", placeholder: "Brief summary of the post (shown in listings)" %>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<!-- Featured Image -->
|
|
64
|
+
<div>
|
|
65
|
+
<%= f.label :featured_image, "Featured Image", class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
66
|
+
<% if @post.featured_image.attached? %>
|
|
67
|
+
<div class="mb-4">
|
|
68
|
+
<%= image_tag @post.featured_image, class: "max-w-md h-auto rounded-lg border border-gray-300", alt: @post.title %>
|
|
69
|
+
<p class="text-xs text-gray-500 mt-2">Current featured image</p>
|
|
70
|
+
</div>
|
|
71
|
+
<% end %>
|
|
72
|
+
<%= f.file_field :featured_image,
|
|
73
|
+
accept: "image/*",
|
|
74
|
+
class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-blue-600 focus:outline-solid file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100" %>
|
|
75
|
+
<p class="text-xs text-gray-500 mt-1">Upload a featured image for this post. Recommended size: 1200x630px for best display.</p>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<!-- Body Content -->
|
|
81
|
+
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
82
|
+
<h2 class="text-lg font-semibold text-gray-900 mb-6">Content</h2>
|
|
83
|
+
<%= f.label :body, class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
84
|
+
<%= f.rich_text_area :body, class: "w-full" %>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<!-- Publishing Options -->
|
|
88
|
+
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
|
89
|
+
<h2 class="text-lg font-semibold text-gray-900 mb-6">Publishing</h2>
|
|
90
|
+
|
|
91
|
+
<div class="space-y-6">
|
|
92
|
+
<!-- Status -->
|
|
93
|
+
<div>
|
|
94
|
+
<%= f.label :status, class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
95
|
+
<%= f.select :status,
|
|
96
|
+
LeanCms::Post.statuses.keys.map { |s| [s.titleize, s] },
|
|
97
|
+
{},
|
|
98
|
+
class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-blue-600 focus:outline-solid" %>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Published At -->
|
|
102
|
+
<div>
|
|
103
|
+
<%= f.label :published_at, "Publish Date & Time", class: "block text-sm font-medium text-gray-700 mb-2" %>
|
|
104
|
+
<%= f.datetime_local_field :published_at,
|
|
105
|
+
value: (@post.published_at || Time.current).strftime("%Y-%m-%dT%H:%M"),
|
|
106
|
+
class: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-blue-600 focus:outline-solid" %>
|
|
107
|
+
<p class="text-xs text-gray-500 mt-1">Posts will only be visible if published and the date/time has passed.</p>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- Form Actions -->
|
|
113
|
+
<div class="flex items-center justify-end space-x-4 bg-gray-50 rounded-lg p-6 border border-gray-200">
|
|
114
|
+
<%= link_to "Cancel", lean_cms_posts_path, class: "px-4 py-2 text-gray-700 hover:text-gray-900 font-medium transition-colors" %>
|
|
115
|
+
<%= f.submit @post.new_record? ? "Create Post" : "Update Post",
|
|
116
|
+
class: "px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-500 transition-colors font-medium" %>
|
|
117
|
+
</div>
|
|
118
|
+
<% end %>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<% content_for :title, "Edit Post" %>
|
|
2
|
+
|
|
3
|
+
<div class="mb-8">
|
|
4
|
+
<div class="flex items-center text-sm text-gray-600 mb-4">
|
|
5
|
+
<%= link_to "Posts", lean_cms_posts_path, class: "hover:text-gray-900" %>
|
|
6
|
+
<svg class="w-4 h-4 mx-2" fill="currentColor" viewBox="0 0 20 20">
|
|
7
|
+
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
|
8
|
+
</svg>
|
|
9
|
+
<span class="text-gray-900">Edit Post</span>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="flex items-center justify-between">
|
|
13
|
+
<div>
|
|
14
|
+
<h1 class="text-3xl font-bold text-gray-900"><%= @post.title %></h1>
|
|
15
|
+
<p class="text-gray-600 mt-2">Last edited by <%= @post.last_edited_by&.email_address %></p>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<% if @post.versions.any? %>
|
|
19
|
+
<div class="text-sm text-gray-600">
|
|
20
|
+
<%= link_to "#", class: "inline-flex items-center px-3 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors" do %>
|
|
21
|
+
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
22
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
23
|
+
</svg>
|
|
24
|
+
View History (<%= @post.versions.count %>)
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<%= render "form", post: @post %>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<% content_for :title, "Posts" %>
|
|
2
|
+
|
|
3
|
+
<div class="flex justify-between items-center mb-8">
|
|
4
|
+
<div>
|
|
5
|
+
<h1 class="text-3xl font-bold text-gray-900">Posts</h1>
|
|
6
|
+
<p class="text-gray-600 mt-2">Manage your blog posts and portfolio items</p>
|
|
7
|
+
</div>
|
|
8
|
+
<%= link_to new_lean_cms_post_path, class: "inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-500 transition-colors" do %>
|
|
9
|
+
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
10
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
|
|
11
|
+
</svg>
|
|
12
|
+
New Post
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<% if @posts.any? %>
|
|
17
|
+
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
|
|
18
|
+
<div class="overflow-x-auto">
|
|
19
|
+
<table class="w-full">
|
|
20
|
+
<thead>
|
|
21
|
+
<tr class="border-b border-gray-200 bg-gray-50">
|
|
22
|
+
<th class="text-left px-6 py-3 text-xs font-semibold text-gray-600 uppercase tracking-wider">Title</th>
|
|
23
|
+
<th class="text-left px-6 py-3 text-xs font-semibold text-gray-600 uppercase tracking-wider">Type</th>
|
|
24
|
+
<th class="text-left px-6 py-3 text-xs font-semibold text-gray-600 uppercase tracking-wider">Status</th>
|
|
25
|
+
<th class="text-left px-6 py-3 text-xs font-semibold text-gray-600 uppercase tracking-wider">Author</th>
|
|
26
|
+
<th class="text-left px-6 py-3 text-xs font-semibold text-gray-600 uppercase tracking-wider">Published</th>
|
|
27
|
+
<th class="text-right px-6 py-3 text-xs font-semibold text-gray-600 uppercase tracking-wider">Actions</th>
|
|
28
|
+
</tr>
|
|
29
|
+
</thead>
|
|
30
|
+
<tbody class="divide-y divide-gray-200">
|
|
31
|
+
<% @posts.each do |post| %>
|
|
32
|
+
<tr class="hover:bg-gray-50 transition-colors">
|
|
33
|
+
<td class="px-6 py-4">
|
|
34
|
+
<div class="font-medium text-gray-900"><%= post.title %></div>
|
|
35
|
+
<div class="text-sm text-gray-500 mt-1"><%= truncate(post.excerpt, length: 80) if post.excerpt.present? %></div>
|
|
36
|
+
</td>
|
|
37
|
+
<td class="px-6 py-4">
|
|
38
|
+
<% if post.content_blog? %>
|
|
39
|
+
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
|
|
40
|
+
Blog
|
|
41
|
+
</span>
|
|
42
|
+
<% else %>
|
|
43
|
+
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
|
44
|
+
Portfolio
|
|
45
|
+
</span>
|
|
46
|
+
<% end %>
|
|
47
|
+
</td>
|
|
48
|
+
<td class="px-6 py-4">
|
|
49
|
+
<% if post.published? %>
|
|
50
|
+
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
|
51
|
+
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
|
52
|
+
<circle cx="10" cy="10" r="3"/>
|
|
53
|
+
</svg>
|
|
54
|
+
Published
|
|
55
|
+
</span>
|
|
56
|
+
<% else %>
|
|
57
|
+
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
|
|
58
|
+
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
|
59
|
+
<circle cx="10" cy="10" r="3"/>
|
|
60
|
+
</svg>
|
|
61
|
+
Draft
|
|
62
|
+
</span>
|
|
63
|
+
<% end %>
|
|
64
|
+
</td>
|
|
65
|
+
<td class="px-6 py-4 text-sm text-gray-600">
|
|
66
|
+
<%= post.author&.email_address %>
|
|
67
|
+
</td>
|
|
68
|
+
<td class="px-6 py-4 text-sm text-gray-600">
|
|
69
|
+
<%= post.published_at ? post.published_at.strftime("%b %d, %Y") : "—" %>
|
|
70
|
+
</td>
|
|
71
|
+
<td class="px-6 py-4 text-right">
|
|
72
|
+
<div class="flex items-center justify-end space-x-3">
|
|
73
|
+
<%= link_to edit_lean_cms_post_path(post), class: "text-blue-600 hover:text-blue-800 transition-colors" do %>
|
|
74
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
75
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
|
|
76
|
+
</svg>
|
|
77
|
+
<% end %>
|
|
78
|
+
<%= button_to lean_cms_post_path(post), method: :delete, data: { turbo_confirm: "Are you sure you want to delete this post?" }, class: "text-red-600 hover:text-red-800 transition-colors" do %>
|
|
79
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
80
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
|
81
|
+
</svg>
|
|
82
|
+
<% end %>
|
|
83
|
+
</div>
|
|
84
|
+
</td>
|
|
85
|
+
</tr>
|
|
86
|
+
<% end %>
|
|
87
|
+
</tbody>
|
|
88
|
+
</table>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
<% else %>
|
|
92
|
+
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-12 text-center">
|
|
93
|
+
<svg class="w-16 h-16 mx-auto text-gray-400 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
94
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
|
95
|
+
</svg>
|
|
96
|
+
<h3 class="text-lg font-medium text-gray-900 mb-2">No posts yet</h3>
|
|
97
|
+
<p class="text-gray-600 mb-6">Get started by creating your first blog post or portfolio item.</p>
|
|
98
|
+
<%= link_to "Create Post", new_lean_cms_post_path, class: "inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-500 transition-colors" %>
|
|
99
|
+
</div>
|
|
100
|
+
<% end %>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<% content_for :title, "New Post" %>
|
|
2
|
+
|
|
3
|
+
<div class="mb-8">
|
|
4
|
+
<div class="flex items-center text-sm text-gray-600 mb-4">
|
|
5
|
+
<%= link_to "Posts", lean_cms_posts_path, class: "hover:text-gray-900" %>
|
|
6
|
+
<svg class="w-4 h-4 mx-2" fill="currentColor" viewBox="0 0 20 20">
|
|
7
|
+
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
|
8
|
+
</svg>
|
|
9
|
+
<span class="text-gray-900">New Post</span>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<h1 class="text-3xl font-bold text-gray-900">Create New Post</h1>
|
|
13
|
+
<p class="text-gray-600 mt-2">Write a new blog post or add a portfolio item</p>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<%= render "form", post: @post %>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<% content_for :title, "Login" %>
|
|
2
|
+
|
|
3
|
+
<h1 class="lc-auth-title">Sign in</h1>
|
|
4
|
+
|
|
5
|
+
<%= form_with url: lean_cms_session_path, class: "lc-auth-form" do |form| %>
|
|
6
|
+
<div class="lc-auth-field">
|
|
7
|
+
<%= form.label :email_address, "Email address" %>
|
|
8
|
+
<%= form.email_field :email_address,
|
|
9
|
+
required: true, autofocus: true, autocomplete: "username",
|
|
10
|
+
placeholder: "you@example.com",
|
|
11
|
+
value: params[:email_address],
|
|
12
|
+
class: "lc-auth-input" %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="lc-auth-field">
|
|
16
|
+
<%= form.label :password, "Password" %>
|
|
17
|
+
<%= form.password_field :password,
|
|
18
|
+
required: true, autocomplete: "current-password",
|
|
19
|
+
placeholder: "Enter your password",
|
|
20
|
+
maxlength: 72,
|
|
21
|
+
class: "lc-auth-input" %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="lc-auth-actions">
|
|
25
|
+
<%= form.submit "Sign in", class: "lc-auth-btn" %>
|
|
26
|
+
<%= link_to "Forgot password?", lean_cms_new_password_path, class: "lc-auth-link" %>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|