layered-ui-rails 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66f25fc8de77c680a94870df09f140d2b8a1f771f471ea67c8681ff13778a18e
4
- data.tar.gz: ed31e153c6db83a3c9ededf98d72b21d573a26ec5d50067ff5d6a6a378d5c74c
3
+ metadata.gz: '099ffddb556cf8f7763737d433421fe787fedc50889917d08d921966e1d183e9'
4
+ data.tar.gz: 066df3ddbff22c075f8b6169d63c43221be4a2dbda828bc9a3dbe0122f54444a
5
5
  SHA512:
6
- metadata.gz: d966b18183ed83f167c188685428e1844ac8b2710ff69ddb641c9e507372163ed40a8b1a318a2714823f8f69b58aaa89e7f420125d6c67f84d9f889215570226
7
- data.tar.gz: d5dbe151878a2f9e21306c9f2464f195ad5401f62c6438dcbe5ddab3a5f1d39a6f988f774371b0143f99cb0cc399ef1e9f1989a5becaca1479df7eaa520115a7
6
+ metadata.gz: 7fe8acf89093fcc834ac1e97a4a7fe61645a1086634984abf1866244aa4960e2f0b38f0e62031680f71520f18371b1118bdf1c40656c796c23b36cb326a2666b
7
+ data.tar.gz: 9d0e94c5c93f70d92442f2f0b12187e196676d7291a64f9996b35f5682773429d9d8b6e1bb4452eb64469e48ac127963ff543dabdab92ec6db00f27e5fd9cc3f
data/AGENTS.md CHANGED
@@ -22,6 +22,12 @@ Guidance for AI agents working in this repository.
22
22
 
23
23
  ## Conventions
24
24
 
25
- - Document new styles in the dummy app. Use `l-ui` classes only there, no extra Tailwind.
25
+ - Use "layered-ui-rails" not "Layered UI" when referring to the project
26
+ - Use normal dashes '-' not long ones '—'
27
+ - Locale: Favour en-GB (British English), unless terms are defined by technical standards (e.g. LICENSE, COLOR).
26
28
  - Titles: capitalise first word only (e.g. "This title")
27
- - WCAG 2.2 AA compliance. Importmap for JS (no bundler).
29
+ - Document new styles in the dummy app
30
+ - Use l-ui classes only in engine views, with no additional Tailwind utilities, as Tailwind classes referenced only inside the engine will not be generated by the host app’s build
31
+ - Dummy app documentation pages may use additional Tailwind utilities, but should favour l-ui classes where possible
32
+ - Retain WCAG 2.2 AA compliance
33
+ - Importmap for JS (no bundler)
data/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. This projec
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.1] - 2026-02-17
8
+
9
+ ### Added
10
+
11
+ - Accent color tokens (`--accent`, `--accent-foreground`) for easy brand color customisation - primary buttons, active tabs, and active navigation items all inherit from these two variables
12
+ - `layered:ui:create_overrides` generator creates a color overrides file that is preserved across upgrades
13
+ - Bundled Manrope and Inter fonts as self-hosted woff2 files, removing the dependency on Google Fonts CDN
14
+ - CI workflow with GitHub Actions
15
+ - Kamal deployment support for the dummy app
16
+
17
+ ### Changed
18
+
19
+ - Active navigation items and tabs now use the accent color instead of the foreground color
20
+ - Install generator now also creates the overrides file and imports it into `application.css`
21
+ - Header icon and logo elements include `w-auto` to prevent layout shift
22
+
23
+ ### Removed
24
+
25
+ - Google Fonts preconnect links from the application layout
26
+
7
27
  ## [0.1.0] - 2026-02-16
8
28
 
9
29
  Initial release.
data/README.md CHANGED
@@ -1,8 +1,29 @@
1
1
  # layered-ui-rails
2
2
 
3
- Open source, minimalist, responsive, accessible UI system with light and dark theme support - and a touch of glass.
4
-
5
- An open source, Rails 8+ engine that provides WCAG 2.2 AA compliant design tokens, Tailwind CSS utilities, and Stimulus controllers for theme switching, mobile navigation, slide-out panels, modals, and tabs. Ships as pure frontend with no server-side dependencies beyond Rails and Tailwind CSS.
3
+ [![CI](https://github.com/layered-ai-public/layered-ui-rails/actions/workflows/ci.yml/badge.svg)](https://github.com/layered-ai-public/layered-ui-rails/actions/workflows/ci.yml)
4
+ [![WCAG 2.2 AA](https://img.shields.io/badge/WCAG_2.2-AA-green)](https://www.w3.org/WAI/WCAG22/quickref/)
5
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+
7
+ An open source, Rails 8+ engine that provides WCAG 2.2 AA compliant design tokens, Tailwind CSS utilities, and Stimulus controllers for theme switching, mobile navigation, slide-out panels, modals, and tabs. Ships as pure frontend with no server-side dependencies beyond Rails and Tailwind CSS. See the [live demo](https://layered-ui-rails.layered.ai).
8
+
9
+ <table align="center">
10
+ <tr>
11
+ <td align="center">
12
+ <img src="test/dummy/app/assets/images/light_desktop.webp" alt="Light theme (desktop)" height="300">
13
+ <img src="test/dummy/app/assets/images/light_mobile.webp" alt="Light theme (mobile)" height="300">
14
+ </td>
15
+ <td width="20"></td>
16
+ <td align="center">
17
+ <img src="test/dummy/app/assets/images/dark_desktop.webp" alt="Dark theme (desktop)" height="300">
18
+ <img src="test/dummy/app/assets/images/dark_mobile.webp" alt="Dark theme (mobile)" height="300">
19
+ </td>
20
+ </tr>
21
+ <tr>
22
+ <td align="center"><em>Light theme (desktop and mobile)</em></td>
23
+ <td></td>
24
+ <td align="center"><em>Dark theme (desktop and mobile)</em></td>
25
+ </tr>
26
+ </table>
6
27
 
7
28
  ## Getting started
8
29
 
@@ -21,10 +42,6 @@ The install generator will:
21
42
  Then update your application layout to render the engine layout:
22
43
 
23
44
  ```erb
24
- <% content_for :l_ui_navigation_items do %>
25
- <%= l_ui_navigation_item "Home", root_path %>
26
- <% end %>
27
-
28
45
  <%= render template: "layouts/layered_ui/application" %>
29
46
  ```
30
47
 
@@ -42,6 +59,8 @@ Then update your application layout to render the engine layout:
42
59
  - **WCAG 2.2 AA compliant** - skip links, focus indicators, ARIA attributes, and 4.5:1 contrast ratios
43
60
  - **Components** - buttons, forms, surfaces, tables, tabs, notices, badges, conversations, modals, and pagination
44
61
  - **Optional integrations** - Devise authentication and Pagy pagination with styled views
62
+ - **Customisable branding** - Override the default logos and icons and colors
63
+ - **Google Lighthouse** - `layered-ui-rails` scores a [perfect 100](test/dummy/app/assets/images/lighthouse.webp) across all four Google Lighthouse categories - performance, accessibility, best practices, and SEO
45
64
 
46
65
  ## Documentation
47
66
 
@@ -58,6 +77,18 @@ cd test/dummy && bin/rails db:setup && bin/dev
58
77
 
59
78
  The dummy app serves as both a living style guide and a test harness, with interactive examples and code snippets for every component.
60
79
 
80
+ ### Deploying the dummy app
81
+
82
+ The dummy app can be deployed with [Kamal](https://kamal-deploy.org). Set the required environment variables and deploy from `test/dummy`:
83
+
84
+ ```bash
85
+ cd test/dummy
86
+ export KAMAL_DEPLOY_IP=<server-ip>
87
+ export KAMAL_DEPLOY_DOMAIN=<domain>
88
+ export KAMAL_SSH_KEY=<path-to-ssh-key>
89
+ kamal deploy
90
+ ```
91
+
61
92
  ## Contributing
62
93
 
63
94
  This project is still in its early days. We welcome issues, feedback, and ideas - they genuinely help shape the direction of the project. That said, we're holding off on accepting pull requests until after the 1.0 release so we can stay focused on getting the core foundations right. Once we're there, we'd love to open things up to broader contributions. Thanks for your patience and interest!
@@ -12,14 +12,32 @@
12
12
  * This structure improves readability, maintainability, and makes diffs easier to review.
13
13
  */
14
14
 
15
+ /* Fonts */
16
+
17
+ @font-face {
18
+ font-family: 'Manrope';
19
+ src: url('layered_ui/manrope.woff2') format('woff2');
20
+ font-weight: 300 700;
21
+ font-display: swap;
22
+ }
23
+
24
+ @font-face {
25
+ font-family: 'Inter';
26
+ src: url('layered_ui/inter.woff2') format('woff2');
27
+ font-weight: 300 700;
28
+ font-display: swap;
29
+ }
30
+
15
31
  /* Variants */
16
32
 
17
33
  @variant dark (&:where(.dark, .dark *));
18
34
 
19
- /* Colours */
35
+ /* Colors */
20
36
 
21
37
  @layer base {
22
38
  :root {
39
+ --accent: 0 0% 9%;
40
+ --accent-foreground: 0 0% 100%;
23
41
  --background: 0 0% 100%;
24
42
  --foreground: 0 0% 13%;
25
43
  --foreground-muted: 0 0% 29%;
@@ -27,8 +45,8 @@
27
45
  --ring: 0 0% 13%;
28
46
  --surface: 0 0% 96%;
29
47
  --surface-active: 0 0% 91%;
30
- --button-primary-bg: 0 0% 9%;
31
- --button-primary-text: 0 0% 100%;
48
+ --button-primary-bg: var(--accent);
49
+ --button-primary-text: var(--accent-foreground);
32
50
  --danger: 0 72% 38%;
33
51
  --danger-light: 0 100% 97%;
34
52
  --danger-text: 0 72% 35%;
@@ -43,6 +61,8 @@
43
61
  }
44
62
 
45
63
  .dark {
64
+ --accent: 0 0% 100%;
65
+ --accent-foreground: 0 0% 9%;
46
66
  --background: 0 0% 0%;
47
67
  --foreground: 0 0% 89%;
48
68
  --foreground-muted: 0 0% 71%;
@@ -50,8 +70,8 @@
50
70
  --ring: 0 0% 89%;
51
71
  --surface: 0 0% 8%;
52
72
  --surface-active: 0 0% 16%;
53
- --button-primary-bg: 0 0% 100%;
54
- --button-primary-text: 0 0% 9%;
73
+ --button-primary-bg: var(--accent);
74
+ --button-primary-text: var(--accent-foreground);
55
75
  --danger: 0 85% 60%;
56
76
  --danger-light: 0 93% 15%;
57
77
  --danger-text: 0 85% 64%;
@@ -114,6 +134,8 @@
114
134
  @theme {
115
135
  --font-manrope: 'Manrope', ui-sans-serif, system-ui, sans-serif;
116
136
  --font-inter: 'Inter', ui-sans-serif, system-ui, sans-serif;
137
+ --color-accent: hsl(var(--accent));
138
+ --color-accent-foreground: hsl(var(--accent-foreground));
117
139
  --color-background: hsl(var(--background));
118
140
  --color-foreground: hsl(var(--foreground));
119
141
  --color-foreground-muted: hsl(var(--foreground-muted));
@@ -293,7 +315,7 @@
293
315
  }
294
316
 
295
317
  .l-ui-header__icon {
296
- @apply h-5.5;
318
+ @apply h-5.5 w-auto;
297
319
  }
298
320
 
299
321
  .l-ui-header__icon--light {
@@ -313,7 +335,7 @@
313
335
  }
314
336
 
315
337
  .l-ui-header__logo {
316
- @apply h-5.5;
338
+ @apply h-5.5 w-auto;
317
339
  }
318
340
 
319
341
  .l-ui-header__logo--light {
@@ -422,7 +444,7 @@
422
444
  .l-ui-navigation__item--active {
423
445
  @apply navigation__item
424
446
  font-bold
425
- text-foreground;
447
+ text-accent;
426
448
 
427
449
  &::after {
428
450
  content: "▸";
@@ -446,7 +468,7 @@
446
468
  .l-ui-navigation__item--active {
447
469
  @apply bg-transparent
448
470
  font-bold
449
- text-foreground;
471
+ text-accent;
450
472
 
451
473
  &::after {
452
474
  content: "▸";
@@ -790,8 +812,8 @@
790
812
 
791
813
  .l-ui-tabs__tab--active {
792
814
  @apply tabs__tab
793
- text-foreground
794
- border-foreground;
815
+ text-accent
816
+ border-accent;
795
817
  }
796
818
 
797
819
  .l-ui-tabs__panel {
@@ -18,10 +18,6 @@
18
18
  <link rel="icon" href="<%= asset_path('layered_ui/icon_dark.svg') %>" media="(prefers-color-scheme: dark)">
19
19
  <link rel="apple-touch-icon" href="<%= asset_path('layered_ui/apple_touch_icon.png') %>">
20
20
 
21
- <link rel="preconnect" href="https://fonts.googleapis.com">
22
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
23
- <link href="https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
24
-
25
21
  <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
26
22
  <%= javascript_importmap_tags %>
27
23
  </head>
@@ -2,7 +2,7 @@ module Layered
2
2
  module Ui
3
3
  module Generators
4
4
  class CopyAssetsGenerator < Rails::Generators::Base
5
- desc "Copy layered-ui CSS assets into the host application"
5
+ desc "Copy layered-ui-rails CSS assets into the host application"
6
6
 
7
7
  def self.source_root
8
8
  Layered::Ui::Engine.root
@@ -0,0 +1,106 @@
1
+ module Layered
2
+ module Ui
3
+ module Generators
4
+ class CreateOverridesGenerator < Rails::Generators::Base
5
+ desc "Create a layered-ui-rails color overrides file in the host application"
6
+
7
+ OVERRIDES_PATH = "app/assets/tailwind/layered_ui_overrides.css"
8
+
9
+ def create_overrides_file
10
+ if File.exist?(OVERRIDES_PATH)
11
+ say "Overrides file already exists at #{OVERRIDES_PATH}, skipping", :yellow
12
+ return
13
+ end
14
+
15
+ create_file OVERRIDES_PATH, overrides_content
16
+ end
17
+
18
+ private
19
+
20
+ def overrides_content
21
+ <<~CSS
22
+ /*
23
+ * layered-ui-rails color overrides
24
+ *
25
+ * Uncomment and edit any variable below to customise the UI.
26
+ * This file is NOT overwritten by the install generator, so your
27
+ * changes are preserved when you upgrade layered-ui-rails.
28
+ *
29
+ * Values are HSL channels: <hue> <saturation>% <lightness>%
30
+ * Example: --accent: 220 80% 55%;
31
+ */
32
+
33
+ /* ----------------------------------------------------------------
34
+ * Tier 1 - Accent color
35
+ *
36
+ * Set a single brand color. Primary buttons, active tabs, and
37
+ * active navigation items all inherit from these two variables.
38
+ * ---------------------------------------------------------------- */
39
+
40
+ :root {
41
+ /* --accent: 0 0% 9%; */
42
+ /* --accent-foreground: 0 0% 100%; */
43
+ }
44
+
45
+ .dark {
46
+ /* --accent: 0 0% 100%; */
47
+ /* --accent-foreground: 0 0% 9%; */
48
+ }
49
+
50
+ /* ----------------------------------------------------------------
51
+ * Tier 2 - Full color overrides
52
+ *
53
+ * Override any individual token. Uncomment only the ones you need.
54
+ * ---------------------------------------------------------------- */
55
+
56
+ /*
57
+ :root {
58
+ --background: 0 0% 100%;
59
+ --foreground: 0 0% 13%;
60
+ --foreground-muted: 0 0% 29%;
61
+ --border: 0 0% 91%;
62
+ --ring: 0 0% 13%;
63
+ --surface: 0 0% 96%;
64
+ --surface-active: 0 0% 91%;
65
+ --button-primary-bg: var(--accent);
66
+ --button-primary-text: var(--accent-foreground);
67
+ --danger: 0 72% 38%;
68
+ --danger-light: 0 100% 97%;
69
+ --danger-text: 0 72% 35%;
70
+ --success-bg: 142 76% 65%;
71
+ --success-text: 142 76% 13%;
72
+ --warning-bg: 48 96% 65%;
73
+ --warning-text: 48 96% 15%;
74
+ --error-bg: 0 84% 75%;
75
+ --error-text: 0 93% 12%;
76
+ --backdrop: 0 0% 0%;
77
+ }
78
+
79
+ .dark {
80
+ --background: 0 0% 0%;
81
+ --foreground: 0 0% 89%;
82
+ --foreground-muted: 0 0% 71%;
83
+ --border: 0 0% 16%;
84
+ --ring: 0 0% 89%;
85
+ --surface: 0 0% 8%;
86
+ --surface-active: 0 0% 16%;
87
+ --button-primary-bg: var(--accent);
88
+ --button-primary-text: var(--accent-foreground);
89
+ --danger: 0 85% 60%;
90
+ --danger-light: 0 93% 15%;
91
+ --danger-text: 0 85% 64%;
92
+ --success-bg: 142 76% 15%;
93
+ --success-text: 142 76% 80%;
94
+ --warning-bg: 48 96% 15%;
95
+ --warning-text: 48 96% 80%;
96
+ --error-bg: 0 93% 12%;
97
+ --error-text: 0 84% 75%;
98
+ --backdrop: 0 0% 0%;
99
+ }
100
+ */
101
+ CSS
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -2,7 +2,7 @@ module Layered
2
2
  module Ui
3
3
  module Generators
4
4
  class ImportCssGenerator < Rails::Generators::Base
5
- desc "Add layered-ui CSS import to the host application"
5
+ desc "Add layered-ui-rails CSS import to the host application"
6
6
 
7
7
  def add_css_import
8
8
  application_css = "app/assets/tailwind/application.css"
@@ -11,16 +11,24 @@ module Layered
11
11
 
12
12
  content = File.read(application_css)
13
13
  import_line = '@import "./layered_ui";'
14
+ overrides_line = '@import "./layered_ui_overrides";'
14
15
 
15
- return if content.include?(import_line)
16
+ unless content.include?(import_line)
17
+ if content.include?('@import "tailwindcss"')
18
+ inject_into_file application_css, "\n#{import_line}", after: '@import "tailwindcss";'
19
+ say "Added import to #{application_css}", :green
20
+ else
21
+ append_to_file application_css, "\n#{import_line}\n"
22
+ say "Appended import to #{application_css}", :green
23
+ end
24
+ end
25
+
26
+ # Re-read in case we just modified it
27
+ content = File.read(application_css)
16
28
 
17
- # Insert after the first @import "tailwindcss" line
18
- if content.include?('@import "tailwindcss"')
19
- inject_into_file application_css, "\n#{import_line}", after: '@import "tailwindcss";'
20
- say "Added import to #{application_css}", :green
21
- else
22
- append_to_file application_css, "\n#{import_line}\n"
23
- say "Appended import to #{application_css}", :green
29
+ unless content.include?(overrides_line)
30
+ inject_into_file application_css, "\n#{overrides_line}", after: import_line
31
+ say "Added overrides import to #{application_css}", :green
24
32
  end
25
33
  end
26
34
  end
@@ -2,7 +2,7 @@ module Layered
2
2
  module Ui
3
3
  module Generators
4
4
  class ImportJsGenerator < Rails::Generators::Base
5
- desc "Add layered-ui JavaScript import to the host application"
5
+ desc "Add layered-ui-rails JavaScript import to the host application"
6
6
 
7
7
  def add_js_import
8
8
  application_js = "app/javascript/application.js"
@@ -2,7 +2,7 @@ module Layered
2
2
  module Ui
3
3
  module Generators
4
4
  class InstallGenerator < Rails::Generators::Base
5
- desc "Install layered-ui into the host application"
5
+ desc "Install layered-ui-rails into the host application"
6
6
 
7
7
  def check_dependencies
8
8
  unless Gem.loaded_specs.key?("tailwindcss-rails")
@@ -19,6 +19,10 @@ module Layered
19
19
  invoke "layered:ui:copy_assets"
20
20
  end
21
21
 
22
+ def create_overrides
23
+ invoke "layered:ui:create_overrides"
24
+ end
25
+
22
26
  def import_css
23
27
  invoke "layered:ui:import_css"
24
28
  end
@@ -11,6 +11,7 @@ module Layered
11
11
  end
12
12
 
13
13
  initializer "layered-ui-rails.assets" do |app|
14
+ app.config.assets.paths << Engine.root.join("app/assets/fonts")
14
15
  app.config.assets.paths << Engine.root.join("app/assets/images")
15
16
  app.config.assets.paths << Engine.root.join("app/javascript")
16
17
  end
@@ -1,5 +1,5 @@
1
1
  module Layered
2
2
  module Ui
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: layered-ui-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - layered.ai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-02-16 00:00:00.000000000 Z
11
+ date: 2026-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -168,6 +168,8 @@ files:
168
168
  - README.md
169
169
  - Rakefile
170
170
  - TRADEMARK.md
171
+ - app/assets/fonts/layered_ui/inter.woff2
172
+ - app/assets/fonts/layered_ui/manrope.woff2
171
173
  - app/assets/images/layered_ui/apple_touch_icon.png
172
174
  - app/assets/images/layered_ui/icon_dark.svg
173
175
  - app/assets/images/layered_ui/icon_light.svg
@@ -207,6 +209,7 @@ files:
207
209
  - app/views/layouts/layered_ui/application.html.erb
208
210
  - config/importmap.rb
209
211
  - lib/generators/layered/ui/copy_assets_generator.rb
212
+ - lib/generators/layered/ui/create_overrides_generator.rb
210
213
  - lib/generators/layered/ui/import_css_generator.rb
211
214
  - lib/generators/layered/ui/import_js_generator.rb
212
215
  - lib/generators/layered/ui/install_generator.rb