Skip to content

Commit 3ee706f

Browse files
Serve engine CSS via tailwindcss-rails engine support (#88)
* Serve engine CSS via tailwindcss-rails engine support Replace the copy-based CSS install with tailwindcss-rails' Rails engine support: the engine's stylesheet is now imported straight from the gem, so it stays in sync with the installed version instead of being copied into the host app at install time. - Move app/assets/tailwind/layered/ui/styles.css to the convention path app/assets/tailwind/layered_ui/engine.css (engine_name is layered_ui) - Remove CopyAssetsGenerator; ImportCssGenerator now injects @import "../builds/tailwind/layered_ui"; - Switch the engine layout to stylesheet_link_tag "tailwind" so propshaft's :app glob no longer emits a stray link to the generated intermediate file - Update README, gemspec post-install message, SKILL.md, AGENTS.md, dummy install docs, and CHANGELOG (flagging the breaking install-flow change) Compiled output is byte-identical to the previous build; fonts and masked SVG icons resolve unchanged. All tests pass. * Build dummy Tailwind CSS before running tests The engine layout now links the compiled build via stylesheet_link_tag "tailwind", which propshaft requires to exist - unlike the previous :app glob that silently tolerated a missing build. On a clean checkout (e.g. CI) there is no app/assets/builds/tailwind.css, so the integration tests raised "asset 'tailwind.css' was not found in the load path". Make the test task depend on app:tailwindcss:build so the CSS (and the engine entry point under builds/tailwind/) is compiled first. * Update AGENTS/CLAUDE generator description for engine-support install flow
1 parent 0c3d3e4 commit 3ee706f

16 files changed

Lines changed: 46 additions & 82 deletions

File tree

.claude/skills/layered-ui-rails/SKILL.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ bundle add layered-ui-rails
2020
bin/rails generate layered:ui:install
2121
```
2222

23-
The generator copies `layered_ui.css` into `app/assets/tailwind/`, adds the CSS import to `application.css`, and adds the JS import to `application.js`.
23+
The generator adds `@import "../builds/tailwind/layered_ui";` to `application.css` (the engine's CSS is served straight from the gem via tailwindcss-rails' engine support), creates a `layered_ui_overrides.css` file for theme customisations, and adds the JS import to `application.js`.
2424

2525
Then render the engine layout from your application layout. Place all `content_for` blocks **above** the render call - the engine layout reads them when it renders, so they must be defined first:
2626

@@ -181,7 +181,7 @@ All controllers use the `l-ui--` namespace and are auto-registered via importmap
181181
Override CSS custom properties after the engine import. Values are full CSS colors - `oklch()` is recommended for perceptually uniform mixing and consistent contrast, but `#hex`, `rgb()`, and keywords also work. A converter such as https://oklch.com/ can help translate from hex/rgb.
182182

183183
```css
184-
@import "./layered_ui";
184+
@import "../builds/tailwind/layered_ui";
185185

186186
:root {
187187
--accent: oklch(0.58 0.19 255);
@@ -217,8 +217,8 @@ Layered::Ui.current_user_method = :current_member # default: :current_user
217217

218218
## Common issues
219219

220-
- **Tailwind classes not generated** - The host app's Tailwind build only sees classes in the host app's templates. Use `l-ui-` classes (which are in the copied CSS) rather than raw Tailwind utilities when styling engine-provided patterns.
221-
- **Missing styles** - Ensure `@import "./layered_ui";` is in `app/assets/tailwind/application.css`.
220+
- **Tailwind classes not generated** - The host app's Tailwind build only sees classes in the host app's templates. Use `l-ui-` classes (which are defined in the engine CSS) rather than raw Tailwind utilities when styling engine-provided patterns.
221+
- **Missing styles** - Ensure `@import "../builds/tailwind/layered_ui";` is in `app/assets/tailwind/application.css`. The import resolves to a file generated by tailwindcss-rails' engine support; it is created automatically by `tailwindcss:build`/`watch` (and `assets:precompile`), so run a build (e.g. `bin/dev`) if the file is missing.
222222
- **Missing JS controllers** - Ensure `import "layered_ui"` is in `app/javascript/application.js`.
223223

224224
## Further reference

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ Guidance for AI agents working in this repository.
66

77
- **Entry:** `require "layered-ui-rails"``lib/layered/ui.rb``lib/layered/ui/engine.rb`
88
- **Engine:** importmap, assets, Pagy helpers when present; helpers: `AuthenticationHelper`, `NavigationHelper`, `PagyHelper`
9-
- **CSS** `app/assets/tailwind/layered/ui/styles.css`: OKLCH tokens, `.dark` on `<html>`, `@theme` utilities (`bg-background`, etc.), BEM components (`.l-ui-button--primary`, etc.). Layout: 63px header, 256px sidebar, 320px panel. WCAG 2.2 AA.
9+
- **CSS** `app/assets/tailwind/layered_ui/engine.css` (the tailwindcss-rails engine entry point): OKLCH tokens, `.dark` on `<html>`, `@theme` utilities (`bg-background`, etc.), BEM components (`.l-ui-button--primary`, etc.). Layout: 63px header, 256px sidebar, 320px panel. WCAG 2.2 AA.
1010
- **CSS `@apply`:** Multi-line with grouping, following the Prettier Tailwind plugin order: layout → sizing → spacing → typography → backgrounds → borders → effects → transitions → interactivity. Within each group, follow Tailwind's own ordering (not alphabetical). State variants (`hover:`, `focus:`, `active:`, `disabled:`) and responsive prefixes (`sm:`, `md:`, `lg:`) are grouped with their base utility. Single utilities may stay on one line.
11-
- **Generators:** `bin/rails generate layered:ui:install` (copy CSS, import CSS, import JS)
11+
- **Generators:** `bin/rails generate layered:ui:install` (import engine CSS via `@import "../builds/tailwind/layered_ui"`, create overrides file, import JS)
1212
- **JS** `app/javascript/layered_ui/`: Stimulus controllers registered as `l-ui--theme`, `l-ui--navigation`, `l-ui--panel`, `l-ui--modal`, `l-ui--tabs`
1313
- **Layout yields** (prefixed `l_ui_`): `:l_ui_navigation_items`, `:l_ui_panel_heading`, `:l_ui_panel_body`, `:l_ui_body_class`
1414
- `:l_ui_body_class` modifiers: `l-ui-body--always-show-navigation` (pins nav as sidebar on desktop), `l-ui-body--hide-header` (hides header and collapses its space)

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
All notable changes to this project will be documented in this file. This project follows [Semantic Versioning](https://semver.org/).
44

5+
## [Unreleased]
6+
7+
### Changed
8+
9+
- **Breaking (install flow):** the engine's CSS is now served directly from the gem using [tailwindcss-rails' engine support](https://github.com/rails/tailwindcss-rails#rails-engines-support-experimental) instead of being copied into the host app. The install generator no longer creates `app/assets/tailwind/layered_ui.css`; instead it adds `@import "../builds/tailwind/layered_ui";` to your `application.css`. The CSS now stays in sync with the installed gem version automatically - no need to re-run the generator after upgrading.
10+
- The engine layout now links the compiled Tailwind build explicitly (`stylesheet_link_tag "tailwind"`) rather than the `:app` bundle, matching tailwindcss-rails' own convention and avoiding a stray link to the engine's intermediate build file.
11+
- Moved the engine's source stylesheet from `app/assets/tailwind/layered/ui/styles.css` to `app/assets/tailwind/layered_ui/engine.css` (the path tailwindcss-rails' engine support expects).
12+
13+
### Removed
14+
15+
- `CopyAssetsGenerator` (`layered:ui:copy_assets`), which copied the engine CSS into the host app. It is replaced by the engine-support import above.
16+
17+
### Migration
18+
19+
Re-run `bin/rails generate layered:ui:install` (it adds the new import without duplicating existing ones), then delete the now-unused copied file at `app/assets/tailwind/layered_ui.css` and remove its `@import "./layered_ui";` line from `application.css`. Your `layered_ui_overrides.css` and any customisations are unaffected.
20+
521
## [0.17.0] - 2026-05-19
622

723
### Added

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ bin/rails generate layered:ui:install
7676
```
7777

7878
The install generator will:
79-
- Copy `layered_ui.css` to `app/assets/tailwind/`
80-
- Add `@import "./layered_ui";` to your `application.css`
79+
- Add `@import "../builds/tailwind/layered_ui";` to your `application.css` (the engine's CSS is served straight from the gem via [tailwindcss-rails' engine support](https://github.com/rails/tailwindcss-rails#rails-engines-support-experimental), so it stays in sync when you upgrade)
80+
- Create `app/assets/tailwind/layered_ui_overrides.css` for your theme customisations (never overwritten on re-install)
8181
- Add `import "layered_ui"` to your `application.js`
8282

8383
Then update your application layout to render the engine layout. Place any `content_for` blocks **above** the render call - the engine layout reads them when it renders, so they must be defined first:
@@ -101,7 +101,7 @@ All colors are CSS custom properties on `:root` using a two-tier system:
101101

102102
```css
103103
/* app/assets/tailwind/application.css */
104-
@import "./layered_ui";
104+
@import "../builds/tailwind/layered_ui";
105105

106106
:root {
107107
--accent: oklch(0.58 0.19 255);

Rakefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@ Rake::TestTask.new(:test) do |t|
1313
t.verbose = false
1414
end
1515

16+
# The engine layout links the compiled Tailwind build (stylesheet_link_tag
17+
# "tailwind"), so the dummy app's CSS must be built before integration tests
18+
# run - otherwise propshaft raises "asset 'tailwind.css' was not found". This
19+
# also generates the engine entry point under app/assets/builds/tailwind/.
20+
task test: "app:tailwindcss:build"
21+
1622
task default: :test

app/views/layouts/layered_ui/application.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
<%# Apply dark class before paint to prevent white flash on reload %>
2222
<script>try{var s=localStorage.getItem("theme");(s==="dark"||(!s&&matchMedia("(prefers-color-scheme:dark)").matches))&&document.documentElement.classList.add("dark")}catch(e){}</script>
23-
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
23+
<%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
2424
<%= yield(:l_ui_head) %>
2525
<%= javascript_importmap_tags %>
2626
</head>

layered-ui-rails.gemspec

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ Gem::Specification.new do |spec|
4848
bin/rails generate layered:ui:install
4949
5050
This command will:
51-
• Copy the layered UI CSS to your host app at app/assets/tailwind/layered_ui.css
52-
• This approach ensures the CSS is processed with your host app's Tailwind configuration
53-
• Add an import statement to your app/assets/tailwind/application.css
51+
• Add `@import "../builds/tailwind/layered_ui";` to your app/assets/tailwind/application.css
52+
• The engine's CSS is served directly from the gem via tailwindcss-rails' engine
53+
support, so it is compiled with your host app's Tailwind configuration and stays
54+
in sync automatically when you upgrade
55+
• Create app/assets/tailwind/layered_ui_overrides.css for your theme customisations
5456
• Add `import "layered_ui"` to your app/javascript/application.js (just after `import "@hotwired/turbo-rails"`, if present)
5557
5658
If these imports already exist, they will not be duplicated.

lib/generators/layered/ui/copy_assets_generator.rb

Lines changed: 0 additions & 30 deletions
This file was deleted.

lib/generators/layered/ui/import_css_generator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def add_css_import
1010
return unless File.exist?(application_css)
1111

1212
content = File.read(application_css)
13-
import_line = '@import "./layered_ui";'
13+
import_line = '@import "../builds/tailwind/layered_ui";'
1414
overrides_line = '@import "./layered_ui_overrides";'
1515

1616
unless content.include?(import_line)

0 commit comments

Comments
 (0)