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
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: cf29b9988643df801321311e1154d6f553ad2919ecede28dec23027a8ef57a96
|
|
4
|
+
data.tar.gz: fea9f113f47e67371e5f97a97bbe80342ed0206bd5512befc629e12067079f2f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 54d383a8799e2391a5f7ac84d1a3aa07ac332798a7394866ce98b5cab46c11614d7fc5be719aa9cba5e33e18fdcb04693e0ea73aba9d3a36f555c2e03e2fe0f7
|
|
7
|
+
data.tar.gz: 230440bd456f36ab053e8855968ef6f189eec98b04b0cd75aab11aeec902b8c4c710c064a3f937063ea7637ea1593738deaac2ba41cf87997d1b3eed9faa978d
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Lean CMS will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.2.12] — 2026-05-15
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **`lean_cms:sync:{pull,push,stage,start,finish}` now abort with a clear message on non-SQLite adapters.** These tasks `cp` SQLite database files directly and have always been SQLite-specific; the new guard prevents accidental no-ops or confusing errors on Postgres/MySQL hosts. `lean_cms:sync:{lock,unlock,status,workflow}` are unaffected — they only toggle a `LeanCms::Setting` and work on any adapter. Task descriptions updated to reflect the SQLite-only scope.
|
|
14
|
+
|
|
15
|
+
### Verified
|
|
16
|
+
- **Postgres compatibility POC.** Fresh Rails 8 + `--database=postgresql` host, install generator, all 7 gem-shipped migrations (`lean_cms_*`, PaperTrail, Action Text, Active Storage, Noticed), `lean_cms:load_structure`, and the rich_text association all worked end-to-end with zero gem changes. The gem's schema is Rails-DSL-only — happy path remains SQLite, but Postgres (and likely MySQL) installs work out of the box for hosts that prefer them. Docs at leancms.dev to be updated separately.
|
|
17
|
+
|
|
18
|
+
## [0.2.11] — 2026-05-14
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **`cms_google_analytics_tag` helper.** Renders a GA4 gtag.js snippet using the measurement ID stored in `LeanCms::Setting.get("google_analytics_id")`. Returns an empty string when the setting is blank — safe to call unconditionally from your layout's `<head>`. Admins set the ID via `/lean-cms/settings` without touching code. Example value: `G-XXXXXXXXXX`.
|
|
22
|
+
|
|
23
|
+
```erb
|
|
24
|
+
<head>
|
|
25
|
+
<!-- ... -->
|
|
26
|
+
<%= cms_google_analytics_tag %>
|
|
27
|
+
</head>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## [0.2.10] — 2026-05-14
|
|
31
|
+
|
|
32
|
+
Install-flow polish — plugs three remaining "fresh install doesn't fully work" gaps surfaced bootstrapping the demo site, all related to gem-side expectations of host-side wiring.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- **Gem now ships the Noticed table migrations.** `noticed_events` + `noticed_notifications` were the last unbundled tables the gem's admin notifications bell needed; hosts previously had to run `bin/rails noticed:install:migrations` separately. New `db/migrate/20260514000004_create_noticed_tables.rb` uses `create_table … if_not_exists: true` so installs that ran `noticed:install:migrations` independently are unaffected.
|
|
36
|
+
- **Engine initializer drops an `actiontext.css` stub** into the host's `app/assets/stylesheets/` on boot (mirrors the existing `lean_cms.edit_controls_css` initializer). The gem's admin layout calls `stylesheet_link_tag "actiontext"` from day one, so the file has to exist before `bin/rails action_text:install` would normally run. Only written once — hosts can edit / replace freely.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- **Gem partials now degrade gracefully when host User model lacks optional methods.** `_notifications_bell.html.erb` short-circuits via `current_user.respond_to?(:notifications)` — hosts that don't want Noticed integration can opt out by just leaving the association off. `_header.html.erb` falls back to `email_address.split("@").first` when `current_user.display_name` is undefined, and to `email_address` when `permissions_summary` is undefined.
|
|
40
|
+
- **Install generator's "Wire up your User model" instructions now show the optional `display_name`, `permissions_summary`, and `has_many :notifications` snippets** alongside the required permission predicates, with a comment noting they're optional but the admin uses them nicely when present.
|
|
41
|
+
|
|
42
|
+
## [0.2.9] — 2026-05-14
|
|
43
|
+
|
|
44
|
+
Extracts the body of `lean_cms:load_structure` out of the Rake task and into a callable service so background jobs and scripts can reseed content without `require 'rake'` / `Rails.application.load_tasks` / `task.reenable; task.invoke` gymnastics.
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- **`LeanCms::Loader` service class** at `lib/lean_cms/loader.rb`. Same behavior as `lean_cms:load_structure` but callable from anywhere:
|
|
48
|
+
```ruby
|
|
49
|
+
result = LeanCms::Loader.new.load!
|
|
50
|
+
result.created # => 28
|
|
51
|
+
result.updated # => 0
|
|
52
|
+
```
|
|
53
|
+
Optional kwargs: `yaml_path:` (default `Rails.root.join("config/lean_cms_structure.yml")`), `system_user:` (default: first super-admin or first user), `logger:` (default: silent — pass `Rails.logger` from a job or `Logger.new($stdout)` from a script). Raises `LeanCms::Loader::StructureFileMissing` or `LeanCms::Loader::NoUsersFound` instead of `exit 1` so callers can rescue meaningfully.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
- **`lean_cms:load_structure` Rake task is now a thin wrapper** that delegates to `LeanCms::Loader`. Same stdout output, same `exit 1` on the two error cases, so existing CI / deploy scripts that shell out to `rake` are unaffected. ~230 lines down to ~20.
|
|
57
|
+
|
|
58
|
+
## [0.2.8] — 2026-05-14
|
|
59
|
+
|
|
60
|
+
Small ergonomic follow-up to v0.2.7.
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
- **`cms_admin_bar` helper.** Wrapper around `render "lean_cms/shared/admin_bar"` so hosts don't have to remember the partial path. Available everywhere `LeanCms::PageContentHelper` is included.
|
|
64
|
+
- **Install generator output now documents the admin bar wiring.** New step 5 in the post-install instructions shows the exact `<body>` snippet hosts should paste into their public layout to surface the bar.
|
|
65
|
+
|
|
66
|
+
## [0.2.7] — 2026-05-14
|
|
67
|
+
|
|
68
|
+
Polish pass after putting the demo live at `demo.leancms.dev`. One bug fix, two ergonomic additions hosts can lean on instead of rebuilding themselves.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
- **`LeanCms::PageContent.find_or_initialize_content` actually finds existing records now.** The lookup used `where(page: page, section: section, key: key).first`, but `where(page: ...)` resolves to the `belongs_to :page` association — emitting `WHERE page_id = NULL` and missing every existing record. Re-running `lean_cms:load_structure` (e.g. to pick up new YAML fields) was crashing on the SQLite unique index for every row. Now uses an explicit string-column comparison via `where("page = ? AND section = ? AND key = ?", …)`. Same shape of fix as the validation patches in v0.2.5.
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
- **`lean_cms/shared/_admin_bar` partial.** The fixed-top admin strip with the Inline Editing toggle, Help, Admin Dashboard, and Sign Out — previously every Lean CMS host had to copy/paste ~40 lines of ERB into their own public layout. Now hosts just `<%= render "lean_cms/shared/admin_bar" %>` from their layout and get the whole widget. The Admin Dashboard button reads its color from `LeanCms.primary_color`. Push the body's top padding down ~40px (e.g. Tailwind `pt-10`) when `current_user&.has_any_cms_permission?` is true so it doesn't overlap your header.
|
|
75
|
+
- **`LeanCms.docs_url` configuration option** (default `https://leancms.dev/docs/`). Drives the new Help icon in the admin bar and the admin-side `_header.html.erb`. Override in `config/initializers/lean_cms.rb` to point at internal docs instead.
|
|
76
|
+
|
|
77
|
+
## [0.2.6] — 2026-05-14
|
|
78
|
+
|
|
79
|
+
Two more demo-bootstrap fixes on top of v0.2.5 — `cards_section` was crashing with a `String#updated_at` error, and `bullets_section` was rendering silently empty even when bullet data existed.
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
- **`LeanCms::BaseComponent#cache_key` handles the String-slug `page` form.** The cache key called `page&.updated_at&.to_i` assuming `page` was always a `LeanCms::Page` record. In the standard helper-driven usage `cards_section("offerings")`, `page` is the slug String (`"trips"`) and `String#updated_at` blew up. Now branches: uses `page.updated_at` when it's a Page record, falls back to `LeanCms::PageContent.where(page: slug).maximum(:updated_at)` when it's a slug — preserves `touch: true` invalidation through the legacy path.
|
|
83
|
+
- **`LeanCms::BulletsSectionComponent` template rewritten.** The previous template split a `content_tag :div do %>` block across two `if can_edit_cms?` guards (open in one, close in another) plus an `<% return %>` inside the cache block. The result rendered as completely empty markup whenever bullets data was present — every bullets section on the public site showed only its heading with a large blank gap below. New template captures the `<ul>` once and wraps it in the edit-controls div only when an editor's signed in. Same behavior for editors, fixes the blank-render bug for public visitors.
|
|
84
|
+
|
|
85
|
+
## [0.2.5] — 2026-05-14
|
|
86
|
+
|
|
87
|
+
Two more bugs surfaced bootstrapping the demo site on top of v0.2.4. Both are pre-existing, both block a fresh install from completing `lean_cms:load_structure`.
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
- **`lean_cms:load_structure` no longer fails with "Page can't be blank" after the v0.2.4 fix.** With the slug now correctly written to the string column via `record[:page] = page`, validation still failed because `validates :page, presence: true` was checking the `belongs_to :page` association (which is `optional: true` and has a nil `page_id` on fresh installs). Replaced with `validate :page_slug_present` reading `read_attribute(:page)` so presence is enforced on the slug column. Added a `page_slug` reader as the public accessor for the slug, alongside the association.
|
|
91
|
+
- **Gem now ships the PaperTrail `versions` table migration.** Four gem models (`PageContent`, `Setting`, `Post`, `FormSubmission`) call `has_paper_trail`, but the install never created the underlying table. The first write on a fresh install crashed with `Could not find table 'versions'`. Added `db/migrate/20260514000001_create_paper_trail_versions.rb`; uses `create_table :versions, if_not_exists: true` plus a guarded `add_index`, so existing installs that ran `paper_trail:install` separately are unaffected.
|
|
92
|
+
- **Gem now ships the Action Text + Active Storage migrations.** `LeanCms::PageContent` calls `has_rich_text :rich_content`, `has_one_attached :image_file`, and `has_many_attached :card_images`; `LeanCms::Setting` calls `has_one_attached :file`. Without these tables, `lean_cms:load_structure` fails the moment it hits the first `rich_text` field. Added `db/migrate/20260514000002_create_action_text_tables.rb` and `db/migrate/20260514000003_create_active_storage_tables.rb`, both fully idempotent — hosts that ran `action_text:install` / `active_storage:install` separately get no-ops.
|
|
93
|
+
- **`(page, section, key)` uniqueness now scopes on the slug column, not the association FK.** The built-in `validates :key, uniqueness: { scope: [:page, :section] }` resolved `:page` to `page_id` (always NULL on fresh installs until the slug → `LeanCms::Page` normalization completes), so the scope collapsed to just `:section`. Records with the same section + key on different pages (e.g. `home/hero/heading` and `trips/hero/heading`) all blocked each other with "Key has already been taken". Replaced with a custom `validate :key_unique_within_page_section` that scopes on the slug via `read_attribute(:page)`.
|
|
94
|
+
|
|
95
|
+
## [0.2.4] — 2026-05-14
|
|
96
|
+
|
|
97
|
+
Surfaced while bootstrapping a fresh demo site from `lean_cms_structure.yml`.
|
|
98
|
+
|
|
99
|
+
### Fixed
|
|
100
|
+
- **`lean_cms:load_structure` no longer crashes with `ActiveRecord::AssociationTypeMismatch: LeanCms::Page expected, got "home"`.** `LeanCms::PageContent` has both a string column `page` (the slug) and a `belongs_to :page, class_name: 'LeanCms::Page'` association (FK on `page_id`). The association shadows the column for mass assignment, so `find_or_initialize_by(page: page_key, …)` was trying to coerce the slug string into a `LeanCms::Page` instance. Introduced `LeanCms::PageContent.find_or_initialize_content(page:, section:, key:)` which bypasses the association setter and writes the slug directly to the string column; the three call sites in the rake task (regular fields, cards, bullets) now route through it. Existing installs continue to work — the helper is purely additive.
|
|
101
|
+
|
|
102
|
+
## [0.2.3] — 2026-05-14
|
|
103
|
+
|
|
104
|
+
Doc-accuracy pass surfaced a couple of small gaps in the gem itself; rolled into this release.
|
|
105
|
+
|
|
106
|
+
### Added
|
|
107
|
+
- **`lean_cms:export_structure` rake task.** Dumps current `LeanCms::PageContent` records back into a YAML file shaped like `lean_cms_structure.yml`, with each field's current value emitted as its `default`. Useful for bootstrapping a second environment from a live database, or for documenting an existing install. Writes to `config/lean_cms_structure_export.yml` by default; override with `OUTPUT=path/to/file.yml`. Image attachments are not included — re-attach via the CMS UI or by copying ActiveStorage blobs.
|
|
108
|
+
- **Install template now generates `posts_per_page` and `portfolio_enabled` config lines.** Both options have existed in `LeanCms::Configuration` since v0.1.0 but were missing from the generated initializer, so most installs didn't know they could be tuned.
|
|
109
|
+
|
|
110
|
+
## [0.2.2] — 2026-05-13
|
|
111
|
+
|
|
112
|
+
The v0.2.1 Tailwind fix was incomplete — it stopped the RoutingError but didn't actually plug the gem's CSS into Tailwind's compile pipeline, so utilities for gem views weren't being emitted. This release adopts `tailwindcss-rails`' native engine support instead.
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
- **Engine name aligned with our Tailwind directory.** Set `engine_name "lean_cms"` explicitly. Rails' default derivation for `LeanCms::Engine` was `lean_cms_engine`, so `Tailwindcss::Engines.bundle` (the built-in `tailwindcss-rails` engine walker) was looking for `app/assets/tailwind/lean_cms_engine/engine.css` — never matched our `app/assets/tailwind/lean_cms/engine.css`. Now `tailwindcss-rails` finds and bundles us natively. Safe to change because we don't use `isolate_namespace` (no route helper prefixing).
|
|
116
|
+
- **Removed our `lean_cms.tailwind_css` initializer entirely.** It was duplicating `Tailwindcss::Engines.bundle` (which `tailwindcss-rails 4.x` runs as a prereq of every `tailwindcss:build` and `tailwindcss:watch`) — except buggily. The v0.2.1 attempt to fix it by inlining engine.css contents broke the relative `@source` paths. Letting tailwindcss-rails do its own thing is correct.
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
- **Install generator now wires up Tailwind.** New `wire_tailwind` step appends `@import "../builds/tailwind/lean_cms.css";` to the host's `app/assets/tailwind/application.css` so Tailwind actually scans the gem's views during compile. If no Tailwind input file is found, prints the line the user needs to paste themselves.
|
|
120
|
+
|
|
121
|
+
## [0.2.1] — 2026-05-13
|
|
122
|
+
|
|
123
|
+
Polish pass on the install + demo flow surfaced by an end-to-end test drive of v0.2.0 on a fresh Rails 8 app. No public API changes.
|
|
124
|
+
|
|
125
|
+
### Fixed
|
|
126
|
+
- **Install generator runs cleanly on fresh apps.** `CreateLeanCmsTables` migration crashed with `Unknown key: :foreign_key` because `t.integer :page_id, foreign_key: { to_table: ... }` is invalid syntax (only `t.references` accepts `foreign_key:`). Removed; the FK was already added at the bottom of the migration via `add_foreign_key`.
|
|
127
|
+
- **Install generator `destination_root.join` crash.** `destination_root` returns a String, not a Pathname. Switched to `File.join`.
|
|
128
|
+
- **Migrations are now portable across host user-table names.** Removed inline `foreign_key: { to_table: :users }` from every `t.references` pointing at the host user table (`lean_cms_posts.author`, `lean_cms_posts.last_edited_by`, `lean_cms_page_contents.last_edited_by`, `lean_cms_sessions.user`, `lean_cms_magic_links.user`). SQLite revalidates *all* FKs in a schema when ALTER triggers a table rebuild — without the host's users table (or with a non-`users` name like Devise's `admins`), this blew up `db:migrate` partway through. Models keep `belongs_to ..., class_name: "User"` for app-level integrity.
|
|
129
|
+
- **Lean CMS no longer requires User-side `has_many` associations.** Was conflicting with Rails 8's built-in `bin/rails generate authentication` which already adds `has_many :sessions`. Gem now uses `LeanCms::Session.create!(user: ...)` / `LeanCms::Session.where(user:).destroy_all` / `LeanCms::MagicLink.where(user:).for_purpose(...)` directly. Host User stays clean.
|
|
130
|
+
- **`lib/lean_cms.rb` now requires its runtime deps eagerly** — `paper_trail`, `view_component`, `kaminari`, `pundit`, `noticed`, `image_processing`, `meta-tags`, `rack-attack`. Hosts that `bundle add lean_cms` were hitting `NameError: uninitialized constant Pundit` when following install instructions, because Bundler doesn't auto-require transitive gemspec deps.
|
|
131
|
+
- **`lean_cms:load_structure` rake task.** Replaced dead `User.cms_admin.first` (pre-0.2 enum scope) with `LeanCms.user_class.constantize.where(is_super_admin: true).first || .first`.
|
|
132
|
+
- **Demo generator crashes.** `directory "views/shared"` referenced a non-existent template directory. Demo's `PagesController` template inherited `LeanCms::Authentication`'s default-protect and locked out public visitors; added `allow_unauthenticated_access`. Demo contact view used non-existent `submit_contact_path` helper; switched to `contact_path`.
|
|
133
|
+
- **Tailwind engine.css 404 on fresh installs.** The `lean_cms.tailwind_css` initializer was writing `@import "/Users/.../lean-cms/app/assets/tailwind/lean_cms/engine.css"` into the host's `app/assets/builds/tailwind/lean_cms.css`. That absolute filesystem path is fine for the Tailwind CLI at compile-time but leaks to the browser as a real HTTP request → Rails `RoutingError`. Initializer now inlines the engine's CSS contents instead of `@import`-ing them, and is guarded with `defined?(Tailwindcss::Engine)` so non-Tailwind hosts don't get the file at all.
|
|
134
|
+
- **Engine initializers no longer scribble into themselves when host == engine.** The Tailwind and edit-controls CSS initializers now `next if app.root == root` (mirroring the migrations initializer), preventing artifacts during in-repo test runs from polluting the gem's working tree.
|
|
135
|
+
|
|
136
|
+
### Added
|
|
137
|
+
- **Minitest test suite** under `test/` with a self-contained dummy Rails 8 app (`test/dummy/`) and in-memory SQLite. Runs via `bundle exec rake test`; CI now invokes it on every push and PR. Initial coverage: engine boot + table names + configuration, `LeanCms::Setting` get/set/JSON/lock helpers, `LeanCms::MagicLink` invitation / password-reset / expiration / invalidation.
|
|
138
|
+
- **`check_user_model` pre-flight in install generator.** Aborts with a clear message if the host's user table doesn't exist or is missing `email_address` / `password_digest` columns. Points consumers at `bin/rails generate authentication` (Rails 8 built-in), Devise, or `rails generate model`. Re-runnable.
|
|
139
|
+
- **`--user=ClassName` flag on the install generator** for hosts whose auth model isn't `User` (e.g. Devise's `Admin`). Drives both the pre-flight check (looks for the `admins` table) and the value written to `LeanCms.user_class` in the generated initializer.
|
|
140
|
+
- **`add_missing_user_columns` step in the install generator.** Diffs the host's user table against the nine Lean CMS-required columns (`name`, `active`, `must_change_password`, `last_login_at`, plus the five permission flags) and generates `db/migrate/add_lean_cms_columns_to_<table>.rb` with only the missing columns. The migration runs as part of the same install — clean install ends with a fully provisioned user table, zero schema hand-editing.
|
|
141
|
+
- **Rails 8 auth conflict detection.** If the host's `ApplicationController` includes `Authentication` (the concern Rails 8's `bin/rails generate authentication` ships), the install generator prints a prominent warning explaining the collision (both concerns define `before_action :require_authentication`; last-included wins; without cleanup `/lean-cms` redirects to `/session/new`). Lists the exact line to remove, files to delete, and routes to drop.
|
|
142
|
+
- **Self-contained auth-page styling.** Login, password reset, password setup pages now ship complete inline CSS keyed off `LeanCms.primary_color` / `secondary_color`. No Tailwind required for the auth flow — drops cleanly into any Rails 8 app with zero CSS framework setup. (Admin / post-login layout is still Tailwind-dependent — separate decision.)
|
|
143
|
+
|
|
144
|
+
### Changed
|
|
145
|
+
- **Pundit is now a gem-internal concern.** `LeanCms::ApplicationController` includes `Pundit::Authorization` itself. Hosts only need `include Pundit::Authorization` in their own AC if they want `authorize` / `policy_scope` available in their own non-CMS controllers — no longer a Lean CMS install step.
|
|
146
|
+
- Install generator's "Wire up your User model" instructions are shorter (no `has_many :sessions` line) and gain a note explaining that the gem uses `LeanCms::Session` directly to stay compatible with Rails 8 auth.
|
|
147
|
+
|
|
148
|
+
## [0.2.0] — 2026-05-13
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
- **Sloth mascot assets** under `app/assets/images/lean_cms/` — favicons (16/32/64), full logo, and 404/500 error illustrations. The gem's admin layouts (`lean_cms/application` and `lean_cms/auth`) now wire in the sloth favicon by default.
|
|
152
|
+
- `LeanCms::Setting.site_favicon_url` — returns the ActiveStorage URL of an uploaded favicon override, or `nil` if none is set. Host apps use this with a fallback to the gem's sloth PNGs for the public site's `<link rel="icon">`.
|
|
153
|
+
- `LeanCms::Setting.update_site_favicon!(io)` and `remove_site_favicon!` — programmatic helpers for the favicon attachment.
|
|
154
|
+
- Favicon upload UI in the Settings page (`/lean-cms/settings`) — admins can upload a PNG/ICO/SVG to override the default sloth on the public site, or remove it to fall back to the default.
|
|
155
|
+
- `has_one_attached :file` on `LeanCms::Setting` — supports per-setting file attachments (currently used only for `site_favicon`).
|
|
156
|
+
|
|
157
|
+
### Fixed
|
|
158
|
+
- `LeanCms::Setting.set` now references `LeanCms::Current.user` (was top-level `Current.user`, which would raise `NameError` after the auth-into-gem migration if any setting was saved from a controller).
|
|
159
|
+
|
|
160
|
+
### Added (continued)
|
|
161
|
+
- **Authentication owned by the gem.** Login, password reset, and magic-link password setup now live under `/lean-cms/login`, `/lean-cms/reset-password`, and `/lean-cms/setup-password/:token`. New gem-owned pieces:
|
|
162
|
+
- `LeanCms::Authentication` controller concern — host's `ApplicationController` includes this to expose `current_user`, `authenticated?`, `start_new_session_for`, and `terminate_session`.
|
|
163
|
+
- `LeanCms::Current` (replaces host `Current`) — `ActiveSupport::CurrentAttributes` with `session` and delegated `user`.
|
|
164
|
+
- `LeanCms::Session` (table `lean_cms_sessions`) and `LeanCms::MagicLink` (table `lean_cms_magic_links`).
|
|
165
|
+
- `LeanCms::SessionsController`, `PasswordsController`, `PasswordSetupController` with branded views rendered via the new `lean_cms/auth` layout.
|
|
166
|
+
- `LeanCms::PasswordsMailer` (`reset`) and `LeanCms::UsersMailer` (`invitation`, `reactivation`, `admin_triggered_password_reset`).
|
|
167
|
+
- Migration `CreateLeanCmsAuthTables` — idempotent (skips if tables already exist).
|
|
168
|
+
- `LeanCms.mailer_from` config — `From:` address for gem-sent emails (default: `noreply@example.com`).
|
|
169
|
+
- `lean_cms:optimize_images` rake task — reads originals from `app/assets/images/source/` and emits resized WebP + same-format fallback variants (default widths: 640/1280/1920) into `app/assets/images/`. Overridable via `WIDTHS`, `WEBP_QUALITY`, `JPEG_QUALITY` env vars. Idempotent (skips outputs newer than source). Powered by libvips via `image_processing`.
|
|
170
|
+
- `lean_cms_picture_tag(name, alt:, widths:, format:, sizes:, **img_options)` helper — renders a `<picture>` with a WebP `<source>` and a JPG/PNG fallback `<img>`, both with proper `srcset` for the configured widths. Defaults to lazy loading and async decoding. Use for static layout images optimized via `lean_cms:optimize_images`.
|
|
171
|
+
|
|
172
|
+
### Changed
|
|
173
|
+
- **BREAKING:** `LeanCms::Authorization` references `LeanCms::Current.user` (was `Current.user`). Hosts that previously relied on a top-level `Current` constant must either include the gem's auth (and remove their own `Current`) or alias `Current = LeanCms::Current`.
|
|
174
|
+
- **BREAKING:** auth URL helpers are namespaced: `lean_cms_new_session_path` (was `new_session_path`), `lean_cms_new_password_path`, `lean_cms_password_setup_path`, etc.
|
|
175
|
+
|
|
176
|
+
### Host migration notes
|
|
177
|
+
Hosts moving from in-app auth to gem auth should:
|
|
178
|
+
1. `bundle update lean_cms`, then `bin/rails db:migrate` to create `lean_cms_sessions` and `lean_cms_magic_links`.
|
|
179
|
+
2. Add `include LeanCms::Authentication` to `ApplicationController` (replacing any local `Authentication` concern).
|
|
180
|
+
3. Update User: `has_many :sessions, class_name: "LeanCms::Session", dependent: :destroy` and the same for `:magic_links`.
|
|
181
|
+
4. Delete local `SessionsController`, `PasswordsController`, `PasswordSetupController`, `Session`, `Current`, `MagicLink`, `PasswordsMailer`, `UsersMailer`, related views, and remove their routes.
|
|
182
|
+
5. Update any references to the unprefixed URL helpers to the `lean_cms_*` namespaced versions.
|
|
183
|
+
6. Optionally drop the old `sessions` and `magic_links` tables in a follow-up migration.
|
|
184
|
+
- `app/assets/tailwind/lean_cms/engine.css` — hooks into `tailwindcss-rails` v4 engine support so the gem's views and Stimulus controllers are scanned when compiling Tailwind CSS in the host app, fixing missing utility classes in production
|
|
185
|
+
- Content Sync card in Settings page showing live lock status with lock/unlock buttons and reason field
|
|
186
|
+
- Lock status banner in the CMS admin layout — displayed prominently across all pages when content is locked, with an inline Unlock button
|
|
187
|
+
|
|
188
|
+
### Fixed
|
|
189
|
+
- Register `app/javascript` with Propshaft's asset load path so Stimulus controllers are served correctly in production
|
|
190
|
+
- Content lock enforcement now also covers `update_field` and `undo_field` inline editing actions (previously only `update` was blocked)
|
|
191
|
+
|
|
192
|
+
## [0.1.0] - 2026-02-21
|
|
193
|
+
|
|
194
|
+
### Added
|
|
195
|
+
- Initial gem extraction from the CAS application
|
|
196
|
+
- Rails Engine with `isolate_namespace LeanCms`
|
|
197
|
+
- **9 content types**: `text`, `rich_text`, `image`, `boolean`, `url`, `color`, `dropdown`, `cards`, `bullets`
|
|
198
|
+
- In-context editing with hover-activated section overlays (`cms_editable_section`)
|
|
199
|
+
- Inline field editing with undo (`editable_content`)
|
|
200
|
+
- `LeanCms::CardsSectionComponent` — renders card grids with drag-to-reorder editor
|
|
201
|
+
- `LeanCms::BulletsSectionComponent` — renders bullet lists with inline editor
|
|
202
|
+
- `LeanCms::EditableContentComponent` — wraps fields with inline edit controls
|
|
203
|
+
- `LeanCms::SectionComponent` — section wrapper with caching and edit overlay
|
|
204
|
+
- Helper API: `page_content`, `page_content_html`, `page_content_image_url`, `page_content?`, `page_section`, `page_structure`, `page_cards`, `page_bullets`
|
|
205
|
+
- `cms_editable_section` and `cms_settings_section` helpers
|
|
206
|
+
- `cards_section` and `bullets_section` component helpers
|
|
207
|
+
- CMS admin: dashboard, page contents editor, posts (blog + portfolio), settings, users, form submissions, notifications, activity log
|
|
208
|
+
- `LeanCms::Setting` — key-value store with caching; convenience methods for site phone, email, address, business hours
|
|
209
|
+
- Content locking for safe database sync workflow
|
|
210
|
+
- `lean_cms:sync` rake task suite — pull, push, stage, start, finish, lock, unlock
|
|
211
|
+
- `rails generate lean_cms:install_kamal_hooks` — installs pre/post deploy hooks
|
|
212
|
+
- Stimulus controllers: `cms-sticky-overlay`, `inline-edit`, `inline-edit-toggle`, `cards-editor`, `settings-inline-edit-sync`, `settings-override`
|
|
213
|
+
- `cms_edit_controls.css` — styles for in-context editing overlays
|
|
214
|
+
- Pundit policies for `PageContent`, `Post`, `Setting`
|
|
215
|
+
- Role-based authorization via `LeanCms::Authorization` concern
|
|
216
|
+
- PaperTrail integration on `PageContent`, `Post`, `Setting`
|
|
217
|
+
- `lean_cms:load_structure` rake task — seeds content from `config/lean_cms_structure.yml`
|
|
218
|
+
- `lean_cms:stats` rake task — prints content field counts by page
|
|
219
|
+
- `LeanCms::SyncHelper` — SQLite database sync between local and production
|
|
220
|
+
|
|
221
|
+
[Unreleased]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.12...HEAD
|
|
222
|
+
[0.2.12]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.11...v0.2.12
|
|
223
|
+
[0.2.11]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.10...v0.2.11
|
|
224
|
+
[0.2.10]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.9...v0.2.10
|
|
225
|
+
[0.2.9]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.8...v0.2.9
|
|
226
|
+
[0.2.8]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.7...v0.2.8
|
|
227
|
+
[0.2.7]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.6...v0.2.7
|
|
228
|
+
[0.2.6]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.5...v0.2.6
|
|
229
|
+
[0.2.5]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.4...v0.2.5
|
|
230
|
+
[0.2.4]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.3...v0.2.4
|
|
231
|
+
[0.2.3]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.2...v0.2.3
|
|
232
|
+
[0.2.2]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.1...v0.2.2
|
|
233
|
+
[0.2.1]: https://github.com/Ovrland-Services/lean-cms/compare/v0.2.0...v0.2.1
|
|
234
|
+
[0.2.0]: https://github.com/Ovrland-Services/lean-cms/compare/v0.1.0...v0.2.0
|
|
235
|
+
[0.1.0]: https://github.com/Ovrland-Services/lean-cms/releases/tag/v0.1.0
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ovrland Services LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/Ovrland-Services/lean-cms/main/app/assets/images/lean_cms/sloth-logo.png" alt="Lean CMS sloth mascot — a sloth reclining on a beanbag chair with sunglasses and a Ruby-stickered laptop" width="240">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Lean CMS</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
A lightweight Rails CMS with in-context editing for marketing sites.
|
|
9
|
+
<br>
|
|
10
|
+
<a href="https://leancms.dev"><strong>leancms.dev</strong></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
Lean CMS is a Rails Engine that adds in-context content editing, page content
|
|
16
|
+
management, blog & portfolio, settings, role-based authentication, and
|
|
17
|
+
notifications to any Rails 8 application. It's designed for marketing sites:
|
|
18
|
+
server-rendered, no separate CMS service to host, and one rake task to
|
|
19
|
+
seed your whole site structure from YAML.
|
|
20
|
+
|
|
21
|
+
## Why Lean CMS
|
|
22
|
+
|
|
23
|
+
- **In-context editing** — content editors hover over any page section to
|
|
24
|
+
reveal an Edit overlay; no separate "admin" interface for day-to-day edits.
|
|
25
|
+
- **You own your design** — the gem never touches your layouts or styles;
|
|
26
|
+
helpers pull content into your own ERB templates.
|
|
27
|
+
- **YAML-defined structure** — every page, section, and field is declared in
|
|
28
|
+
`config/lean_cms_structure.yml` and seeded with one rake task.
|
|
29
|
+
- **Built-in auth** — login, password reset, and magic-link invitations all
|
|
30
|
+
shipped by the gem and namespaced under `/lean-cms`.
|
|
31
|
+
- **9 content types** — `text`, `rich_text`, `image`, `boolean`, `url`,
|
|
32
|
+
`color`, `dropdown`, `cards`, `bullets`.
|
|
33
|
+
- **Version history** — every content edit tracked via PaperTrail; one-click
|
|
34
|
+
undo.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
# Gemfile
|
|
40
|
+
gem "lean_cms"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bundle install
|
|
45
|
+
rails generate lean_cms:install
|
|
46
|
+
rails db:migrate
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then in `app/controllers/application_controller.rb`:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
include LeanCms::Authentication
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
And in `app/helpers/application_helper.rb`:
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
include LeanCms::PageContentHelper
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
See the [Getting Started guide](https://leancms.dev/docs/getting-started/installation/) for the full setup including User-model requirements and YAML structure.
|
|
62
|
+
|
|
63
|
+
> **Heads up — authentication.** Lean CMS ships its own auth (login at `/lean-cms/login`, sessions, magic-link invites). It coexists cleanly with Rails 8's built-in `bin/rails generate authentication` (the install generator detects + warns). **If you're already using Devise or another auth gem**, the gem currently still adds a second login screen — first-class host-auth integration is the v0.3 milestone. See [issue tracker](https://github.com/Ovrland-Services/lean-cms/issues) for status.
|
|
64
|
+
|
|
65
|
+
## A taste of the helper API
|
|
66
|
+
|
|
67
|
+
```erb
|
|
68
|
+
<%# A whole section, hover-editable for admins %>
|
|
69
|
+
<%= cms_editable_section(page: "home", section: "hero", display_title: "Hero") do %>
|
|
70
|
+
<section class="hero">
|
|
71
|
+
<h1><%= editable_content("hero", "heading") %></h1>
|
|
72
|
+
<p><%= editable_content("hero", "subheading") %></p>
|
|
73
|
+
|
|
74
|
+
<% bg = page_content_image_url(@page, "hero", "background") %>
|
|
75
|
+
<% if bg %><%= image_tag bg, class: "absolute inset-0" %><% end %>
|
|
76
|
+
</section>
|
|
77
|
+
<% end %>
|
|
78
|
+
|
|
79
|
+
<%# Responsive optimized <picture> for static layout images %>
|
|
80
|
+
<%= lean_cms_picture_tag "wire-panel",
|
|
81
|
+
alt: "Wiring",
|
|
82
|
+
widths: [640, 1280],
|
|
83
|
+
sizes: "(min-width: 768px) 448px, 100vw",
|
|
84
|
+
class: "rounded-2xl shadow-lg" %>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Requirements
|
|
88
|
+
|
|
89
|
+
- Ruby ≥ 3.2
|
|
90
|
+
- Rails ≥ 8.0
|
|
91
|
+
- SQLite, PostgreSQL, or MySQL (SQLite is the happy path; see [Database support](https://leancms.dev/docs/deployment/database-support/) for the compatibility matrix)
|
|
92
|
+
|
|
93
|
+
## Roadmap
|
|
94
|
+
|
|
95
|
+
Lean CMS is `0.2.x` — pre-1.0, API may shift between minors. Public roadmap:
|
|
96
|
+
|
|
97
|
+
- **v0.2.x** _(current)_: feature-complete CMS surface, in-context editing, hourly-resettable demo. Ships its own auth.
|
|
98
|
+
- **v0.3**: host-auth adapter pattern — first-class integration with Devise / Rodauth / custom-auth hosts. Sibling [`lean-cms-devise-example`](https://github.com/Ovrland-Services/lean-cms) repo as the proving ground + public reference.
|
|
99
|
+
- **v0.4** _(idea stage)_: AI-powered `lean_cms-scraper` companion gem — `bin/rails generate lean_cms:scrape URL=...` writes a starter `lean_cms_structure.yml` from an existing live website.
|
|
100
|
+
|
|
101
|
+
## Demo
|
|
102
|
+
|
|
103
|
+
Live at [demo.leancms.dev](https://demo.leancms.dev) — sign in with `demo@leancms.dev` / `demo123` and edit anything. Content resets every hour at `:00 UTC`. Source: [`Ovrland-Services/lean-cms-demo`](https://github.com/Ovrland-Services/lean-cms-demo).
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT. See [LICENSE](LICENSE).
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|