stimulus_plumbers_tailwind 0.4.5 → 0.4.9
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +12 -15
- data/app/assets/stylesheets/stimulus_plumbers/tailwind/animations.css +18 -0
- data/docs/architecture.md +50 -0
- data/docs/guide.md +23 -0
- data/lib/generators/stimulus_plumbers/tailwind/install/install_generator.rb +61 -0
- data/lib/stimulus_plumbers/tailwind/engine.rb +18 -0
- data/lib/stimulus_plumbers/tailwind/generators/animations_directive.rb +32 -0
- data/lib/stimulus_plumbers/tailwind/generators/sources_directive.rb +29 -0
- data/lib/stimulus_plumbers/tailwind/version.rb +1 -1
- data/lib/stimulus_plumbers/themes/tailwind/button.rb +1 -1
- data/lib/stimulus_plumbers/themes/tailwind/card.rb +1 -1
- data/lib/stimulus_plumbers/themes/tailwind/checklist.rb +65 -0
- data/lib/stimulus_plumbers/themes/tailwind/combobox.rb +1 -1
- data/lib/stimulus_plumbers/themes/tailwind/control.rb +2 -0
- data/lib/stimulus_plumbers/themes/tailwind/form/input.rb +18 -15
- data/lib/stimulus_plumbers/themes/tailwind/icon.rb +10 -3
- data/lib/stimulus_plumbers/themes/tailwind/icons/customs/progress-ring.svg +12 -0
- data/lib/stimulus_plumbers/themes/tailwind/indicator.rb +49 -0
- data/lib/stimulus_plumbers/themes/tailwind/link.rb +1 -1
- data/lib/stimulus_plumbers/themes/tailwind/list.rb +1 -1
- data/lib/stimulus_plumbers/themes/tailwind/ordered_list.rb +66 -0
- data/lib/stimulus_plumbers/themes/tailwind/progress.rb +45 -0
- data/lib/stimulus_plumbers/themes/tailwind/timeline/group.rb +14 -5
- data/lib/stimulus_plumbers/themes/tailwind/timeline.rb +7 -9
- data/lib/stimulus_plumbers/themes/tailwind_theme.rb +8 -0
- data/lib/stimulus_plumbers_tailwind.rb +1 -1
- data/lib/tasks/stimulus_plumbers_tailwind.rake +15 -9
- metadata +13 -3
- data/lib/generators/stimulus_plumbers_tailwind/install/install_generator.rb +0 -78
- data/lib/stimulus_plumbers_tailwind/engine.rb +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7a0a4078d4282a62d21ebdb421fd18c446fe69031dac6ed8f9be663c91957d2
|
|
4
|
+
data.tar.gz: 234ae70da55a34c9be1c655fa40c5d7e9536d6c99c7a75f5f5724df662fc63d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c608f0a0f0513903e3f6224c8750935deee7ccf736791eee048a54dcb421a5a345c7efec685046bd2027a75756ce2b3e3801fdffdc570f71aca9c05e3e86e92a
|
|
7
|
+
data.tar.gz: c1db6f8eb3034534ed893ada8507866529bfe654fd059fb26f22d17ee49951fbd7b4b218f5f121eb47ad4959cdda40185bc3b560b1aa2f80fb1c806d6877a154
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
---
|
|
6
|
+
## [0.4.8](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.5..stimulus-plumbers-tailwind/v0.4.8) - 2026-07-03
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- tailwind install generator ([#154](https://github.com/ryancyq/stimulus-plumbers/issues/154)) - ([db4bda0](https://github.com/ryancyq/stimulus-plumbers/commit/db4bda0b899a463e0608229927c65326233dd3a4)) - Ryan Chang
|
|
11
|
+
- tailwind theme registration + activation (rails only) ([#157](https://github.com/ryancyq/stimulus-plumbers/issues/157)) - ([5998854](https://github.com/ryancyq/stimulus-plumbers/commit/5998854ed2a6ca9c67aa225f3c397e4f7bca7a51)) - Ryan Chang
|
|
12
|
+
- mcp doc update + new tools validations ([#162](https://github.com/ryancyq/stimulus-plumbers/issues/162)) - ([beed1bb](https://github.com/ryancyq/stimulus-plumbers/commit/beed1bb14cbfcb8ec6f757145dc6a461d357c060)) - Ryan Chang
|
|
13
|
+
|
|
5
14
|
---
|
|
6
15
|
## [0.4.4](https://github.com/ryancyq/stimulus-plumbers/compare/stimulus-plumbers-tailwind/v0.4.3..stimulus-plumbers-tailwind/v0.4.4) - 2026-06-30
|
|
7
16
|
|
data/README.md
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
Tailwind CSS v4 theme for [`stimulus_plumbers`](../stimulus-plumbers-rails). Extends the base theme with utility classes for all components.
|
|
8
8
|
|
|
9
|
+
See [docs/guide.md](docs/guide.md) for a quick setup/theming guide.
|
|
10
|
+
|
|
9
11
|
## Requirements
|
|
10
12
|
|
|
11
13
|
- Ruby >= 3.0
|
|
12
|
-
- `stimulus_plumbers` >= 0.
|
|
14
|
+
- `stimulus_plumbers` >= 0.3.1
|
|
13
15
|
- Tailwind CSS v4 in your build toolchain
|
|
14
16
|
|
|
15
17
|
## Installation
|
|
@@ -23,7 +25,7 @@ gem "stimulus_plumbers_tailwind"
|
|
|
23
25
|
bundle install
|
|
24
26
|
```
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
In a Rails app, the theme registers and activates automatically — no config needed. Outside Rails, it only registers; activate it explicitly:
|
|
27
29
|
|
|
28
30
|
```ruby
|
|
29
31
|
StimulusPlumbers.configure do |config|
|
|
@@ -31,21 +33,13 @@ StimulusPlumbers.configure do |config|
|
|
|
31
33
|
end
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
Run the install generator once to inject the required `@source` directive into your Tailwind CSS entry file:
|
|
36
|
+
Run the install generator once to inject the required `@source` directive (and the `stimulus_plumbers` tokens.css + `animations.css` imports) into your Tailwind CSS entry file — see [docs/guide.md](docs/guide.md) for file-detection/override details:
|
|
35
37
|
|
|
36
38
|
```bash
|
|
37
|
-
bin/rails generate
|
|
39
|
+
bin/rails generate stimulus_plumbers:tailwind:install
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
The
|
|
41
|
-
|
|
42
|
-
- `app/assets/stylesheets/application.tailwind.css`
|
|
43
|
-
- `app/assets/stylesheets/application.css`
|
|
44
|
-
- `app/javascript/entrypoints/application.css`
|
|
45
|
-
|
|
46
|
-
Override the detected file for both the generator and rake task with `TAILWIND_CSS_FILE=/path/to/entry.css`.
|
|
47
|
-
|
|
48
|
-
After the initial install, the `@source` path is kept current automatically — no manual re-run needed after `bundle update`. The engine hooks `stimulus_plumbers_tailwind:install` as a prerequisite of:
|
|
42
|
+
After that, the `@source` path is kept current automatically — no manual re-run needed after `bundle update`. The engine hooks `stimulus_plumbers:tailwind:install` as a prerequisite of:
|
|
49
43
|
|
|
50
44
|
- `assets:precompile` (Sprockets and Propshaft both define this task)
|
|
51
45
|
- `tailwindcss:build` (when `tailwindcss-rails` is present)
|
|
@@ -53,7 +47,7 @@ After the initial install, the `@source` path is kept current automatically —
|
|
|
53
47
|
To trigger an update manually without a full compile (useful for debugging or after `bundle update`):
|
|
54
48
|
|
|
55
49
|
```bash
|
|
56
|
-
bin/rails
|
|
50
|
+
bin/rails stimulus_plumbers:tailwind:install
|
|
57
51
|
```
|
|
58
52
|
|
|
59
53
|
## Theming
|
|
@@ -69,9 +63,12 @@ bin/rails stimulus_plumbers_tailwind:install
|
|
|
69
63
|
| `Tailwind::Combobox` | Combobox (date, time, dropdown, typeahead) |
|
|
70
64
|
| `Tailwind::Form` | Form fields, labels, errors |
|
|
71
65
|
| `Tailwind::Icon` | Icon (SVG rendering, icon registry) |
|
|
66
|
+
| `Tailwind::Indicator` | Indicator (dot, pulse, badge) |
|
|
72
67
|
| `Tailwind::Layout` | Layout primitives |
|
|
73
68
|
| `Tailwind::Link` | Link |
|
|
74
69
|
| `Tailwind::List` | List |
|
|
70
|
+
| `Tailwind::OrderedList` | Reorderable list (drag handle, item styling) |
|
|
71
|
+
| `Tailwind::Progress` | Progress bar, progress ring, meter |
|
|
75
72
|
| `Tailwind::Timeline` | Timeline |
|
|
76
73
|
|
|
77
74
|
Custom themes can subclass `TailwindTheme` to override individual methods, or subclass `StimulusPlumbers::Themes::Base` directly.
|
|
@@ -92,7 +89,7 @@ Icons render as inline `<svg>` with `size-6` by default. Override with `class:`:
|
|
|
92
89
|
<%= sp_icon "arrow-left", class: "size-4 text-gray-500" %>
|
|
93
90
|
```
|
|
94
91
|
|
|
95
|
-
**Built-in aliases:** `"close"` → `"x-mark"`, `"calendar"` → `"calendar-days"`.
|
|
92
|
+
**Built-in aliases:** `"close"` → `"x-mark"`, `"download"` → `"arrow-down-tray"`, `"book"` → `"book-open"`, `"edit"` → `"pencil"`, `"email"` → `"envelope"`, `"calendar"` → `"calendar-days"`, `"external-link"` → `"arrow-top-right-on-square"`, `"reveal"` → `"eye"`, `"grip-vertical"` → `"bars-3"`.
|
|
96
93
|
|
|
97
94
|
**Optional `heroicons` gem:** add `gem "heroicons"` to your `Gemfile` to load icons from the gem instead of the bundled files. The theme detects it automatically.
|
|
98
95
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@theme {
|
|
2
|
+
--animate-progress-slide: sp-progress-slide 1.5s ease-in-out infinite;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
@keyframes sp-progress-slide {
|
|
6
|
+
0% { transform: translateX(-100%); }
|
|
7
|
+
100% { transform: translateX(300%); }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* Ring-only; core's transition covers width, not stroke-dashoffset. */
|
|
11
|
+
[data-progress-target="fill"] {
|
|
12
|
+
transition: stroke-dashoffset 0.3s ease;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Track color — kept out of the SVG so consumers can retheme it via CSS. */
|
|
16
|
+
svg[role="progressbar"] .track {
|
|
17
|
+
stroke: var(--sp-color-muted);
|
|
18
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Tailwind Theme Architecture
|
|
2
|
+
|
|
3
|
+
## Module Layout
|
|
4
|
+
|
|
5
|
+
`TailwindTheme` extends `Base` and is split into concern modules under `StimulusPlumbers::Themes::Tailwind::*`. Each module provides CSS class resolution for one component family. The `Icon` module also owns the icon registry (`icons/`).
|
|
6
|
+
|
|
7
|
+
## Constant Ownership Rules
|
|
8
|
+
|
|
9
|
+
- **No local aliases** — never re-export another module's constant (e.g. `MY_CONST = Other::CONST`). Reference the constant directly at the call site.
|
|
10
|
+
- **No prefix redundancy** — name constants after what they represent, not where they live. `Button::VARIANTS` not `Button::BUTTON_VARIANTS`; `Card::VARIANTS` not `Card::CARD_VARIANTS`.
|
|
11
|
+
- **Remove unused constants** — if a constant has no call sites in `schema.rb`, delete it.
|
|
12
|
+
|
|
13
|
+
## Shared Interactive Foundation — `Control::BASE`
|
|
14
|
+
|
|
15
|
+
`Control::BASE` holds CSS shared by all focusable, disableable controls: font weight, transition, focus ring tokens, `disabled:*` states. Components include it via array splat and add their own ring color variable on top.
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
# Composition — correct
|
|
19
|
+
[*Control::BASE, *Button::BASE, "extra-class"].freeze
|
|
20
|
+
|
|
21
|
+
# Duplication — wrong
|
|
22
|
+
["font-medium", "transition-colors", "extra-class"].freeze
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`Control::BASE` is always included first; never duplicate its classes in component constants.
|
|
26
|
+
|
|
27
|
+
## Icon-Only Square Pattern
|
|
28
|
+
|
|
29
|
+
The core gem wraps button/link text in `<span>`. Icon-only renders no `<span>`. The theme detects this via CSS:
|
|
30
|
+
|
|
31
|
+
- `Button::LAYOUT` carries `[&:not(:has(>span))]:aspect-square [&:not(:has(>span))]:px-0`
|
|
32
|
+
- `Link::BUTTON` carries the same two classes
|
|
33
|
+
- `fab`/`fab_outline` types become circles via this mechanism
|
|
34
|
+
|
|
35
|
+
**Do not change the Ruby renderer's `<span>` wrapping contract without updating these theme constants.**
|
|
36
|
+
|
|
37
|
+
## Card Style Pattern
|
|
38
|
+
|
|
39
|
+
Button, Link, Checkbox, and Radio all share a unified card style via the `--card-ring` CSS variable.
|
|
40
|
+
|
|
41
|
+
- `Card::VARIANTS` maps `:default/:success/:destructive/:warning/:info` to `--sp-color-*` values
|
|
42
|
+
- All card-type components reference `Card::VARIANTS.fetch(variant, Card::VARIANTS[:default])`
|
|
43
|
+
- **Button card** (`type: :card`) — `Button::BASE + Button::CARD + Button::TYPES[:card]`; `size:` ignored
|
|
44
|
+
- **Link card** — `Link::CARD` composes `Control::BASE + Card::BASE + Button::CARD`
|
|
45
|
+
- **Checkbox card** — input visible; label uses `has-[:checked]:border-(--card-ring)`
|
|
46
|
+
- **Radio card/button** — input is `hidden peer`; label uses `peer-checked:border-(--card-ring)`
|
|
47
|
+
|
|
48
|
+
## Floating Field Key Ownership
|
|
49
|
+
|
|
50
|
+
Floating-label theme keys (`form_field_floating`, `form_field_floating_group`, `form_field_floating_label`) and their constants (`FLOATING_INPUT_*`, `FLOATING_GROUP_TYPES`, `FLOATING_LABEL_*`) live in `Form::Field` (`form/field.rb`), **not** `Form::Input`. Floating is a field-layout concern, not an input-element concern.
|
data/docs/guide.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Guide
|
|
2
|
+
|
|
3
|
+
Adding this gem registers and activates the Tailwind theme automatically in Rails — no config
|
|
4
|
+
needed. Outside Rails, activate it explicitly with `config.theme.use(:tailwind)`.
|
|
5
|
+
|
|
6
|
+
Run the install generator once to wire the required `@source` directive and the `animations.css`
|
|
7
|
+
import (registers the indeterminate progress bar's slide keyframe via `@theme`) into your Tailwind
|
|
8
|
+
CSS entry file:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bin/rails generate stimulus_plumbers:tailwind:install
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
It re-runs automatically on `assets:precompile`/`tailwindcss:build` after that. File detection and
|
|
15
|
+
the `STIMULUS_PLUMBERS_CSS_ENTRY` override are shared with the core gem — see
|
|
16
|
+
[stimulus-plumbers-rails/docs/guide.md#css-entry-file-detection](../../stimulus-plumbers-rails/docs/guide.md#css-entry-file-detection).
|
|
17
|
+
|
|
18
|
+
Icons: pass a kebab-case name to `sp_icon` or any `icon_leading:`/`icon_trailing:` option (append
|
|
19
|
+
`/solid` for the filled variant) — see [README.md](../README.md#icons) for aliases and the
|
|
20
|
+
optional `heroicons` gem.
|
|
21
|
+
|
|
22
|
+
To implement a custom theme instead of/alongside Tailwind, see
|
|
23
|
+
[stimulus-plumbers-rails/docs/component/theme.md](../../stimulus-plumbers-rails/docs/component/theme.md).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "stimulus_plumbers/generators/css_entrypoint"
|
|
5
|
+
require "stimulus_plumbers/generators/tokens_directive"
|
|
6
|
+
require "stimulus_plumbers/tailwind/generators/animations_directive"
|
|
7
|
+
require "stimulus_plumbers/tailwind/generators/sources_directive"
|
|
8
|
+
|
|
9
|
+
module StimulusPlumbers
|
|
10
|
+
module Tailwind
|
|
11
|
+
module Generators
|
|
12
|
+
class InstallGenerator < Rails::Generators::Base
|
|
13
|
+
include StimulusPlumbers::Generators::CssEntrypoint
|
|
14
|
+
|
|
15
|
+
def install
|
|
16
|
+
css_file = entry_css_file(**css_file_lookup_options)
|
|
17
|
+
return warn_entry_css_not_found(label: "Tailwind CSS", **css_file_lookup_options) unless css_file
|
|
18
|
+
|
|
19
|
+
apply_tokens_directive(css_file)
|
|
20
|
+
apply_animations_directive(css_file)
|
|
21
|
+
apply_sources_directive(css_file)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def css_file_lookup_options
|
|
27
|
+
{
|
|
28
|
+
candidates: StimulusPlumbers::Generators::CssEntrypoint::ENTRY_CANDIDATES,
|
|
29
|
+
env_var: StimulusPlumbers::Generators::CssEntrypoint::STIMULUS_PLUMBERS_CSS_ENTRY
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def apply_tokens_directive(css_file)
|
|
34
|
+
apply_edit(
|
|
35
|
+
css_file,
|
|
36
|
+
StimulusPlumbers::Generators::TokensDirective.directive(from: File.dirname(css_file)),
|
|
37
|
+
stale_pattern: StimulusPlumbers::Generators::TokensDirective.stale_pattern
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def apply_animations_directive(css_file)
|
|
42
|
+
apply_edit(
|
|
43
|
+
css_file,
|
|
44
|
+
AnimationsDirective.directive(from: File.dirname(css_file)),
|
|
45
|
+
anchor_pattern: AnimationsDirective.anchor_pattern,
|
|
46
|
+
stale_pattern: AnimationsDirective.stale_pattern
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def apply_sources_directive(css_file)
|
|
51
|
+
apply_edit(
|
|
52
|
+
css_file,
|
|
53
|
+
SourcesDirective.directive(from: File.dirname(css_file)),
|
|
54
|
+
anchor_pattern: SourcesDirective.anchor_pattern,
|
|
55
|
+
stale_pattern: SourcesDirective.stale_pattern
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Tailwind
|
|
5
|
+
class Engine < ::Rails::Engine
|
|
6
|
+
initializer "stimulus_plumbers_tailwind.register_theme" do
|
|
7
|
+
StimulusPlumbers.configure do |c|
|
|
8
|
+
c.theme.register(:tailwind, StimulusPlumbers::Themes::TailwindTheme)
|
|
9
|
+
c.theme.use(:tailwind)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
rake_tasks do
|
|
14
|
+
load File.join(__dir__, "../../tasks/stimulus_plumbers_tailwind.rake")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
|
|
5
|
+
module StimulusPlumbers
|
|
6
|
+
module Tailwind
|
|
7
|
+
module Generators
|
|
8
|
+
module AnimationsDirective
|
|
9
|
+
GEM_ROOT = File.expand_path("../../../..", __dir__)
|
|
10
|
+
ANIMATIONS_CSS_REL_PATH = "app/assets/stylesheets/stimulus_plumbers/tailwind/animations.css"
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def directive(from:)
|
|
15
|
+
path = Pathname.new(GEM_ROOT).join(ANIMATIONS_CSS_REL_PATH)
|
|
16
|
+
rel = path.relative_path_from(Pathname.new(from))
|
|
17
|
+
%(@import "#{rel}";)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Anchors right after the core tokens.css import so the two asset
|
|
21
|
+
# imports stay grouped, ahead of the tailwindcss import and @source lines.
|
|
22
|
+
def anchor_pattern
|
|
23
|
+
%r{@import "[^"]*tokens\.css";}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def stale_pattern
|
|
27
|
+
%r{@import "[^"]*#{Regexp.escape(ANIMATIONS_CSS_REL_PATH)}";}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
|
|
5
|
+
module StimulusPlumbers
|
|
6
|
+
module Tailwind
|
|
7
|
+
module Generators
|
|
8
|
+
module SourcesDirective
|
|
9
|
+
GEM_NAME = "stimulus_plumbers_tailwind"
|
|
10
|
+
LIB_DIR = File.expand_path("../../..", __dir__)
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def directive(from:)
|
|
15
|
+
rel = Pathname.new(LIB_DIR).relative_path_from(Pathname.new(from))
|
|
16
|
+
%(@source "#{rel}/**/*.rb";)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def anchor_pattern
|
|
20
|
+
%r{@import "tailwindcss"[^;]*;}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stale_pattern
|
|
24
|
+
%r{@source "[^"]*#{Regexp.escape(GEM_NAME)}[^"]*";}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Themes
|
|
5
|
+
module Tailwind
|
|
6
|
+
module Checklist
|
|
7
|
+
WRAPPER_BASE = %w[flex flex-col gap-(--sp-space-1)].freeze
|
|
8
|
+
|
|
9
|
+
ITEM_BASE = [
|
|
10
|
+
*Control::BASE,
|
|
11
|
+
"group/checklist-item flex items-center gap-(--sp-space-2) w-full text-start",
|
|
12
|
+
"px-(--sp-space-2) py-(--sp-space-1)",
|
|
13
|
+
"rounded-(--sp-radius-sm) text-(length:--sp-text-sm)",
|
|
14
|
+
"cursor-pointer select-none text-(--sp-color-fg)",
|
|
15
|
+
"hover:bg-(--sp-color-muted)",
|
|
16
|
+
"has-disabled:cursor-default has-disabled:hover:bg-transparent"
|
|
17
|
+
].freeze
|
|
18
|
+
|
|
19
|
+
INPUT_BASE = [
|
|
20
|
+
*Control::ACCENT,
|
|
21
|
+
"size-(--sp-control-size) rounded-(--sp-radius-sm) shrink-0",
|
|
22
|
+
"border border-(--sp-color-border) bg-(--sp-color-muted)",
|
|
23
|
+
"focus:ring-(length:--sp-focus-ring-width) focus:ring-(--sp-focus-ring-color) focus:outline-none",
|
|
24
|
+
"disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
27
|
+
CONTENT_BASE = %w[flex flex-col flex-1 min-w-0].freeze
|
|
28
|
+
|
|
29
|
+
TITLE_BASE = %w[
|
|
30
|
+
text-(length:--sp-text-sm) font-medium text-(--sp-color-fg)
|
|
31
|
+
group-has-checked/checklist-item:line-through
|
|
32
|
+
group-has-checked/checklist-item:text-(--sp-color-muted-fg)
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
DESCRIPTION_BASE = %w[text-(length:--sp-text-xs) text-(--sp-color-muted-fg)].freeze
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def checklist_classes
|
|
40
|
+
{ classes: klasses(*WRAPPER_BASE) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def checklist_item_classes
|
|
44
|
+
{ classes: klasses(*ITEM_BASE) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def checklist_item_input_classes
|
|
48
|
+
{ classes: klasses(*INPUT_BASE) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def checklist_item_content_classes
|
|
52
|
+
{ classes: klasses(*CONTENT_BASE) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def checklist_item_title_classes
|
|
56
|
+
{ classes: klasses(*TITLE_BASE) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def checklist_item_description_classes
|
|
60
|
+
{ classes: klasses(*DESCRIPTION_BASE) }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -80,21 +80,24 @@ module StimulusPlumbers
|
|
|
80
80
|
|
|
81
81
|
# ── Choice inputs ─────────────────────────────────────────────────────
|
|
82
82
|
CHECKBOX_TYPES = {
|
|
83
|
-
default:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
default: [
|
|
84
|
+
*Control::ACCENT,
|
|
85
|
+
"size-(--sp-control-size) rounded-(--sp-radius-sm) shrink-0",
|
|
86
|
+
"border border-(--sp-color-border) bg-(--sp-color-muted)",
|
|
87
|
+
"focus:ring-(length:--sp-focus-ring-width) focus:ring-(--sp-focus-ring-color) focus:outline-none",
|
|
88
|
+
"disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
|
|
88
89
|
].freeze,
|
|
89
|
-
button:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
button: [
|
|
91
|
+
*Control::ACCENT,
|
|
92
|
+
"size-(--sp-control-size) rounded-(--sp-radius-sm) shrink-0",
|
|
93
|
+
"border border-(--sp-color-border) bg-(--sp-color-muted)",
|
|
94
|
+
"focus:ring-(length:--sp-focus-ring-width) focus:ring-(--sp-focus-ring-color) focus:outline-none",
|
|
95
|
+
"disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
|
|
94
96
|
].freeze,
|
|
95
97
|
card: %w[
|
|
96
98
|
size-(--sp-control-size) rounded-(--sp-radius-sm) shrink-0
|
|
97
99
|
border border-(--sp-color-border) bg-(--sp-color-muted)
|
|
100
|
+
[accent-color:var(--card-ring)] cursor-pointer
|
|
98
101
|
checked:border-(--card-ring)
|
|
99
102
|
focus:ring-(length:--sp-focus-ring-width) focus:ring-(--card-ring) focus:outline-none
|
|
100
103
|
disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer
|
|
@@ -102,11 +105,11 @@ module StimulusPlumbers
|
|
|
102
105
|
}.freeze
|
|
103
106
|
|
|
104
107
|
RADIO_TYPES = {
|
|
105
|
-
default:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
focus:ring-(length:--sp-focus-ring-width) focus:ring-(--sp-focus-ring-color) focus:outline-none
|
|
109
|
-
disabled:opacity-50 disabled:cursor-not-allowed
|
|
108
|
+
default: [
|
|
109
|
+
*Control::ACCENT,
|
|
110
|
+
"size-(--sp-control-size) rounded-full shrink-0",
|
|
111
|
+
"focus:ring-(length:--sp-focus-ring-width) focus:ring-(--sp-focus-ring-color) focus:outline-none",
|
|
112
|
+
"disabled:opacity-50 disabled:cursor-not-allowed"
|
|
110
113
|
].freeze,
|
|
111
114
|
button: %w[hidden].freeze,
|
|
112
115
|
card: %w[hidden].freeze
|
|
@@ -16,7 +16,8 @@ module StimulusPlumbers
|
|
|
16
16
|
"email" => "envelope",
|
|
17
17
|
"calendar" => "calendar-days",
|
|
18
18
|
"external-link" => "arrow-top-right-on-square",
|
|
19
|
-
"reveal" => "eye"
|
|
19
|
+
"reveal" => "eye",
|
|
20
|
+
"grip-vertical" => "bars-3"
|
|
20
21
|
}.freeze
|
|
21
22
|
|
|
22
23
|
ICONS = StimulusPlumbers::Themes::Icons::Registry.new(
|
|
@@ -24,14 +25,20 @@ module StimulusPlumbers
|
|
|
24
25
|
aliases: ALIASES
|
|
25
26
|
)
|
|
26
27
|
|
|
28
|
+
SIZES = {
|
|
29
|
+
sm: "size-(--sp-icon-size-sm)",
|
|
30
|
+
md: "size-(--sp-icon-size-md)",
|
|
31
|
+
lg: "size-(--sp-icon-size-lg)"
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
27
34
|
def icons
|
|
28
35
|
ICONS
|
|
29
36
|
end
|
|
30
37
|
|
|
31
38
|
private
|
|
32
39
|
|
|
33
|
-
def icon_classes
|
|
34
|
-
{ classes:
|
|
40
|
+
def icon_classes(size: :lg)
|
|
41
|
+
{ classes: SIZES.fetch(size, SIZES[:lg]) }
|
|
35
42
|
end
|
|
36
43
|
end
|
|
37
44
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44 44" width="44" height="44" fill="none">
|
|
2
|
+
<circle cx="22" cy="22" r="18" stroke-width="3" class="track"></circle>
|
|
3
|
+
<circle
|
|
4
|
+
cx="22"
|
|
5
|
+
cy="22"
|
|
6
|
+
r="18"
|
|
7
|
+
stroke="currentColor"
|
|
8
|
+
stroke-width="3"
|
|
9
|
+
stroke-linecap="round"
|
|
10
|
+
data-progress-target="fill"
|
|
11
|
+
></circle>
|
|
12
|
+
</svg>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Themes
|
|
5
|
+
module Tailwind
|
|
6
|
+
module Indicator
|
|
7
|
+
VARIANTS = {
|
|
8
|
+
primary: "bg-(--sp-color-primary)",
|
|
9
|
+
secondary: "bg-(--sp-color-secondary)",
|
|
10
|
+
tertiary: "bg-(--sp-color-muted-fg)",
|
|
11
|
+
success: "bg-(--sp-color-success)",
|
|
12
|
+
destructive: "bg-(--sp-color-destructive)",
|
|
13
|
+
warning: "bg-(--sp-color-warning)",
|
|
14
|
+
info: "bg-(--sp-color-info)"
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
DOT = %w[inline-flex size-2.5 rounded-full].freeze
|
|
18
|
+
BADGE = %w[
|
|
19
|
+
inline-flex items-center justify-center
|
|
20
|
+
min-w-5 h-5 px-1
|
|
21
|
+
rounded-full text-(length:--sp-text-xs) font-medium text-white
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
24
|
+
# Establishes the positioning context the pulse ring overlays onto — no margin needed.
|
|
25
|
+
WRAPPER = %w[relative inline-flex items-center justify-center].freeze
|
|
26
|
+
|
|
27
|
+
PULSE_RING = %w[
|
|
28
|
+
absolute inset-0 rounded-full
|
|
29
|
+
bg-(--sp-color-indicator) opacity-75
|
|
30
|
+
animate-ping motion-reduce:animate-none
|
|
31
|
+
].freeze
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def indicator_classes(type: :dot, variant: nil)
|
|
36
|
+
{ classes: klasses(*(type.to_sym == :badge ? BADGE : DOT), VARIANTS.fetch(variant, nil)) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def indicator_wrapper_classes
|
|
40
|
+
{ classes: klasses(*WRAPPER) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def indicator_pulse_classes
|
|
44
|
+
{ classes: klasses(*PULSE_RING) }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Themes
|
|
5
|
+
module Tailwind
|
|
6
|
+
module OrderedList
|
|
7
|
+
# ── Item ──────────────────────────────────────────────────────────────
|
|
8
|
+
ITEM_BASE = [
|
|
9
|
+
*Control::BASE,
|
|
10
|
+
"flex items-center gap-(--sp-space-2) w-full",
|
|
11
|
+
"px-(--sp-space-2) py-(--sp-space-1)",
|
|
12
|
+
"rounded-(--sp-radius-sm) text-(length:--sp-text-sm)",
|
|
13
|
+
"text-(--sp-color-fg)",
|
|
14
|
+
"focus-visible:ring-(--sp-color-primary-ring)",
|
|
15
|
+
"aria-[current]:bg-(--sp-color-primary)/10 aria-[current]:text-(--sp-color-primary)"
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
HANDLE_BASE = %w[
|
|
19
|
+
flex items-center justify-center shrink-0
|
|
20
|
+
stroke-current
|
|
21
|
+
text-(--sp-color-muted-fg)
|
|
22
|
+
cursor-grab active:cursor-grabbing
|
|
23
|
+
touch-none
|
|
24
|
+
].freeze
|
|
25
|
+
|
|
26
|
+
CONTENT_BASE = %w[
|
|
27
|
+
flex flex-col flex-1 min-w-0
|
|
28
|
+
].freeze
|
|
29
|
+
|
|
30
|
+
TITLE_BASE = %w[
|
|
31
|
+
text-(length:--sp-text-sm) font-medium text-(--sp-color-fg)
|
|
32
|
+
].freeze
|
|
33
|
+
|
|
34
|
+
DESCRIPTION_BASE = %w[
|
|
35
|
+
text-(length:--sp-text-xs) text-(--sp-color-muted-fg)
|
|
36
|
+
].freeze
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def ordered_list_classes
|
|
41
|
+
{ classes: klasses("flex flex-col gap-(--sp-space-1) py-(--sp-space-1)") }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ordered_list_item_classes
|
|
45
|
+
{ classes: klasses(*ITEM_BASE) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def ordered_list_item_handle_classes
|
|
49
|
+
{ classes: klasses(*HANDLE_BASE) }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def ordered_list_item_content_classes
|
|
53
|
+
{ classes: klasses(*CONTENT_BASE) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ordered_list_item_title_classes
|
|
57
|
+
{ classes: klasses(*TITLE_BASE) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def ordered_list_item_description_classes
|
|
61
|
+
{ classes: klasses(*DESCRIPTION_BASE) }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StimulusPlumbers
|
|
4
|
+
module Themes
|
|
5
|
+
module Tailwind
|
|
6
|
+
module Progress
|
|
7
|
+
BAR = %w[
|
|
8
|
+
relative w-full h-2 overflow-hidden rounded-full
|
|
9
|
+
bg-(--sp-color-muted)
|
|
10
|
+
].freeze
|
|
11
|
+
|
|
12
|
+
BAR_FILL = %w[
|
|
13
|
+
h-full rounded-full bg-(--sp-color-primary)
|
|
14
|
+
[.sp-progress-indeterminate_&]:animate-progress-slide
|
|
15
|
+
[.sp-progress-indeterminate_&]:motion-reduce:animate-none
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
# Circle stroke/fill live in icons/customs/progress-ring.svg — @source never scans
|
|
19
|
+
# .svg files, so Tailwind classes there are inert.
|
|
20
|
+
# Indeterminate class and utility land on this same svg, so this needs the compound
|
|
21
|
+
# [&.foo] form, not BAR_FILL's [.foo_&] descendant form.
|
|
22
|
+
RING = %w[
|
|
23
|
+
-rotate-90 text-(--sp-color-primary)
|
|
24
|
+
[&.sp-progress-indeterminate]:animate-spin
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
27
|
+
METER = %w[
|
|
28
|
+
w-full h-2 rounded-full
|
|
29
|
+
[&::-webkit-meter-bar]:rounded-full [&::-webkit-meter-bar]:bg-(--sp-color-muted)
|
|
30
|
+
[&::-webkit-meter-optimum-value]:bg-(--sp-color-success)
|
|
31
|
+
[&::-webkit-meter-suboptimum-value]:bg-(--sp-color-warning)
|
|
32
|
+
[&::-webkit-meter-even-less-good-value]:bg-(--sp-color-destructive)
|
|
33
|
+
[&::-moz-meter-bar]:bg-(--sp-color-success)
|
|
34
|
+
].freeze
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def progress_bar_classes = { classes: klasses(*BAR) }
|
|
39
|
+
def progress_bar_fill_classes = { classes: klasses(*BAR_FILL) }
|
|
40
|
+
def progress_ring_classes = { classes: klasses(*RING) }
|
|
41
|
+
def progress_meter_classes = { classes: klasses(*METER) }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -5,22 +5,31 @@ module StimulusPlumbers
|
|
|
5
5
|
module Tailwind
|
|
6
6
|
module Timeline
|
|
7
7
|
module Group
|
|
8
|
-
WRAPPER
|
|
9
|
-
SECTION
|
|
8
|
+
WRAPPER = %w[flex flex-col gap-y-4].freeze
|
|
9
|
+
SECTION = %w[
|
|
10
10
|
p-4
|
|
11
11
|
bg-(--sp-color-bg-muted)
|
|
12
12
|
border border-(--sp-color-border)
|
|
13
13
|
rounded-lg
|
|
14
14
|
].freeze
|
|
15
|
-
DATE
|
|
16
|
-
|
|
15
|
+
DATE = %w[text-base font-semibold text-(--sp-color-fg)].freeze
|
|
16
|
+
LIST_VERTICAL = %w[
|
|
17
|
+
pt-3 flex flex-col
|
|
18
|
+
divide-y divide-(--sp-color-border)
|
|
19
|
+
[&>li]:py-2 [&>li]:first:pt-0 [&>li]:last:pb-0
|
|
20
|
+
].freeze
|
|
21
|
+
LIST_HORIZONTAL = %w[pt-3 flex gap-x-4].freeze
|
|
17
22
|
|
|
18
23
|
private
|
|
19
24
|
|
|
20
25
|
def timeline_group_classes = { classes: klasses(WRAPPER) }
|
|
21
26
|
def timeline_group_section_classes = { classes: klasses(SECTION) }
|
|
22
27
|
def timeline_group_section_date_classes = { classes: klasses(DATE) }
|
|
23
|
-
|
|
28
|
+
|
|
29
|
+
def timeline_group_section_list_classes(orientation: :vertical)
|
|
30
|
+
list = orientation.to_sym == :horizontal ? LIST_HORIZONTAL : LIST_VERTICAL
|
|
31
|
+
{ classes: klasses(list) }
|
|
32
|
+
end
|
|
24
33
|
end
|
|
25
34
|
end
|
|
26
35
|
end
|
|
@@ -18,7 +18,6 @@ module StimulusPlumbers
|
|
|
18
18
|
mt-1 flex shrink-0 size-6 items-center justify-center rounded-full z-10
|
|
19
19
|
bg-(--sp-color-bg) ring-4 ring-(--sp-color-bg)
|
|
20
20
|
].freeze
|
|
21
|
-
ITEM_INDICATOR_DOT_MARK = %w[size-3 rounded-full bg-(--sp-color-indicator)].freeze
|
|
22
21
|
|
|
23
22
|
ITEM_INDICATOR_ICON = %w[
|
|
24
23
|
mt-1 flex shrink-0 size-6 items-center justify-center rounded-full z-10
|
|
@@ -26,7 +25,7 @@ module StimulusPlumbers
|
|
|
26
25
|
ring-4 ring-(--sp-color-bg)
|
|
27
26
|
].freeze
|
|
28
27
|
|
|
29
|
-
ITEM_INDICATOR_ICON_SLOT = %w[
|
|
28
|
+
ITEM_INDICATOR_ICON_SLOT = %w[stroke-current].freeze
|
|
30
29
|
|
|
31
30
|
ITEM_INDICATOR_DOT_HORIZONTAL = %w[
|
|
32
31
|
z-10 flex shrink-0 size-6 items-center justify-center rounded-full
|
|
@@ -50,12 +49,12 @@ module StimulusPlumbers
|
|
|
50
49
|
].freeze
|
|
51
50
|
ITEM_TITLE = %w[mb-1 text-base font-semibold text-(--sp-color-fg)].freeze
|
|
52
51
|
ITEM_HEADING = %w[mb-1].freeze
|
|
53
|
-
ITEM_TRIGGER =
|
|
54
|
-
|
|
55
|
-
text-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
focus-visible:ring-(--sp-color-primary) focus-visible:rounded-sm
|
|
52
|
+
ITEM_TRIGGER = [
|
|
53
|
+
*Control::BASE,
|
|
54
|
+
"w-full text-left text-base font-semibold",
|
|
55
|
+
"text-(--sp-color-fg)",
|
|
56
|
+
"hover:text-(--sp-color-primary)",
|
|
57
|
+
"focus-visible:ring-(--sp-color-primary-ring) focus-visible:rounded-sm"
|
|
59
58
|
].freeze
|
|
60
59
|
ITEM_DESCRIPTION = %w[text-sm text-(--sp-color-muted-fg)].freeze
|
|
61
60
|
ITEM_DETAIL = %w[mt-2 text-sm text-(--sp-color-muted-fg)].freeze
|
|
@@ -93,7 +92,6 @@ module StimulusPlumbers
|
|
|
93
92
|
def timeline_item_description_classes = { classes: klasses(ITEM_DESCRIPTION) }
|
|
94
93
|
def timeline_item_detail_classes = { classes: klasses(ITEM_DETAIL) }
|
|
95
94
|
def timeline_item_actions_classes = { classes: klasses(ITEM_ACTIONS) }
|
|
96
|
-
def timeline_item_indicator_dot_classes = { classes: klasses(ITEM_INDICATOR_DOT_MARK) }
|
|
97
95
|
def timeline_item_connector_classes = { classes: klasses(ITEM_CONNECTOR_HORIZONTAL) }
|
|
98
96
|
def timeline_item_content_classes = { classes: klasses(ITEM_CONTENT_HORIZONTAL) }
|
|
99
97
|
def timeline_track_line_classes = { classes: klasses(TRACK_LINE_VERTICAL) }
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "tailwind/control"
|
|
4
|
+
require_relative "tailwind/checklist"
|
|
4
5
|
require_relative "tailwind/list"
|
|
6
|
+
require_relative "tailwind/ordered_list"
|
|
5
7
|
require_relative "tailwind/avatar"
|
|
6
8
|
require_relative "tailwind/button"
|
|
7
9
|
require_relative "tailwind/button/group"
|
|
@@ -12,14 +14,18 @@ require_relative "tailwind/form"
|
|
|
12
14
|
require_relative "tailwind/form/field"
|
|
13
15
|
require_relative "tailwind/form/input"
|
|
14
16
|
require_relative "tailwind/icon"
|
|
17
|
+
require_relative "tailwind/indicator"
|
|
15
18
|
require_relative "tailwind/layout"
|
|
16
19
|
require_relative "tailwind/link"
|
|
20
|
+
require_relative "tailwind/progress"
|
|
17
21
|
require_relative "tailwind/timeline"
|
|
18
22
|
|
|
19
23
|
module StimulusPlumbers
|
|
20
24
|
module Themes
|
|
21
25
|
class TailwindTheme < Base
|
|
26
|
+
include Tailwind::Checklist
|
|
22
27
|
include Tailwind::List
|
|
28
|
+
include Tailwind::OrderedList
|
|
23
29
|
include Tailwind::Combobox
|
|
24
30
|
include Tailwind::Avatar
|
|
25
31
|
include Tailwind::Button
|
|
@@ -30,8 +36,10 @@ module StimulusPlumbers
|
|
|
30
36
|
include Tailwind::Form::Field
|
|
31
37
|
include Tailwind::Form::Input
|
|
32
38
|
include Tailwind::Icon
|
|
39
|
+
include Tailwind::Indicator
|
|
33
40
|
include Tailwind::Layout
|
|
34
41
|
include Tailwind::Link
|
|
42
|
+
include Tailwind::Progress
|
|
35
43
|
include Tailwind::Timeline
|
|
36
44
|
include Tailwind::Timeline::Group
|
|
37
45
|
|
|
@@ -6,7 +6,7 @@ require_relative "stimulus_plumbers/tailwind/version"
|
|
|
6
6
|
require_relative "stimulus_plumbers/themes/tailwind_theme"
|
|
7
7
|
|
|
8
8
|
if defined?(Rails::Engine)
|
|
9
|
-
require_relative "
|
|
9
|
+
require_relative "stimulus_plumbers/tailwind/engine"
|
|
10
10
|
else
|
|
11
11
|
StimulusPlumbers.configure do |c|
|
|
12
12
|
c.theme.register(:tailwind, StimulusPlumbers::Themes::TailwindTheme)
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
namespace :
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
namespace :stimulus_plumbers do
|
|
4
|
+
namespace :tailwind do
|
|
5
|
+
desc "Add @source directive for stimulus_plumbers_tailwind into Tailwind CSS entry file"
|
|
6
|
+
task(:install) do
|
|
7
|
+
unless ENV["STIMULUS_PLUMBERS_SKIP_INSTALL"]
|
|
8
|
+
require "generators/stimulus_plumbers/tailwind/install/install_generator"
|
|
9
|
+
StimulusPlumbers::Tailwind::Generators::InstallGenerator.new(
|
|
10
|
+
[], {}, { destination_root: Rails.root.to_s }
|
|
11
|
+
).invoke_all
|
|
12
|
+
end
|
|
13
|
+
end
|
|
10
14
|
end
|
|
11
15
|
end
|
|
12
16
|
|
|
13
|
-
Rake::Task["
|
|
17
|
+
Rake::Task["stimulus_plumbers:tailwind:install"].enhance(["environment"]) unless ENV["STIMULUS_PLUMBERS_SKIP_INSTALL"]
|
|
14
18
|
|
|
15
|
-
Rake
|
|
19
|
+
# Hooks into these tasks as a prerequisite; Rake merges rather than overwrites, so order-independent.
|
|
20
|
+
task "assets:precompile" => ["stimulus_plumbers:tailwind:install"]
|
|
21
|
+
task "tailwindcss:build" => ["stimulus_plumbers:tailwind:install"]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stimulus_plumbers_tailwind
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Chang
|
|
@@ -33,13 +33,20 @@ files:
|
|
|
33
33
|
- CHANGELOG.md
|
|
34
34
|
- LICENSE-DEPENDENCIES
|
|
35
35
|
- README.md
|
|
36
|
-
-
|
|
36
|
+
- app/assets/stylesheets/stimulus_plumbers/tailwind/animations.css
|
|
37
|
+
- docs/architecture.md
|
|
38
|
+
- docs/guide.md
|
|
39
|
+
- lib/generators/stimulus_plumbers/tailwind/install/install_generator.rb
|
|
40
|
+
- lib/stimulus_plumbers/tailwind/engine.rb
|
|
41
|
+
- lib/stimulus_plumbers/tailwind/generators/animations_directive.rb
|
|
42
|
+
- lib/stimulus_plumbers/tailwind/generators/sources_directive.rb
|
|
37
43
|
- lib/stimulus_plumbers/tailwind/version.rb
|
|
38
44
|
- lib/stimulus_plumbers/themes/tailwind/avatar.rb
|
|
39
45
|
- lib/stimulus_plumbers/themes/tailwind/button.rb
|
|
40
46
|
- lib/stimulus_plumbers/themes/tailwind/button/group.rb
|
|
41
47
|
- lib/stimulus_plumbers/themes/tailwind/calendar.rb
|
|
42
48
|
- lib/stimulus_plumbers/themes/tailwind/card.rb
|
|
49
|
+
- lib/stimulus_plumbers/themes/tailwind/checklist.rb
|
|
43
50
|
- lib/stimulus_plumbers/themes/tailwind/combobox.rb
|
|
44
51
|
- lib/stimulus_plumbers/themes/tailwind/control.rb
|
|
45
52
|
- lib/stimulus_plumbers/themes/tailwind/form.rb
|
|
@@ -47,6 +54,7 @@ files:
|
|
|
47
54
|
- lib/stimulus_plumbers/themes/tailwind/form/input.rb
|
|
48
55
|
- lib/stimulus_plumbers/themes/tailwind/icon.rb
|
|
49
56
|
- lib/stimulus_plumbers/themes/tailwind/icons/custom.rb
|
|
57
|
+
- lib/stimulus_plumbers/themes/tailwind/icons/customs/progress-ring.svg
|
|
50
58
|
- lib/stimulus_plumbers/themes/tailwind/icons/customs/spinner.svg
|
|
51
59
|
- lib/stimulus_plumbers/themes/tailwind/icons/heroicon.rb
|
|
52
60
|
- lib/stimulus_plumbers/themes/tailwind/icons/heroicons/outline/academic-cap.svg
|
|
@@ -697,14 +705,16 @@ files:
|
|
|
697
705
|
- lib/stimulus_plumbers/themes/tailwind/icons/heroicons/solid/wrench.svg
|
|
698
706
|
- lib/stimulus_plumbers/themes/tailwind/icons/heroicons/solid/x-circle.svg
|
|
699
707
|
- lib/stimulus_plumbers/themes/tailwind/icons/heroicons/solid/x-mark.svg
|
|
708
|
+
- lib/stimulus_plumbers/themes/tailwind/indicator.rb
|
|
700
709
|
- lib/stimulus_plumbers/themes/tailwind/layout.rb
|
|
701
710
|
- lib/stimulus_plumbers/themes/tailwind/link.rb
|
|
702
711
|
- lib/stimulus_plumbers/themes/tailwind/list.rb
|
|
712
|
+
- lib/stimulus_plumbers/themes/tailwind/ordered_list.rb
|
|
713
|
+
- lib/stimulus_plumbers/themes/tailwind/progress.rb
|
|
703
714
|
- lib/stimulus_plumbers/themes/tailwind/timeline.rb
|
|
704
715
|
- lib/stimulus_plumbers/themes/tailwind/timeline/group.rb
|
|
705
716
|
- lib/stimulus_plumbers/themes/tailwind_theme.rb
|
|
706
717
|
- lib/stimulus_plumbers_tailwind.rb
|
|
707
|
-
- lib/stimulus_plumbers_tailwind/engine.rb
|
|
708
718
|
- lib/tasks/stimulus_plumbers_tailwind.rake
|
|
709
719
|
homepage: https://github.com/ryancyq/stimulus-plumbers
|
|
710
720
|
licenses:
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "rails/generators"
|
|
4
|
-
|
|
5
|
-
module StimulusPlumbersTailwind
|
|
6
|
-
module Generators
|
|
7
|
-
class InstallGenerator < Rails::Generators::Base
|
|
8
|
-
GEM_NAME = "stimulus_plumbers_tailwind"
|
|
9
|
-
TAILWIND_CSS_FILE = "TAILWIND_CSS_FILE"
|
|
10
|
-
CSS_CANDIDATES = %w[
|
|
11
|
-
app/assets/stylesheets/application.tailwind.css
|
|
12
|
-
app/assets/stylesheets/application.css
|
|
13
|
-
app/javascript/entrypoints/application.css
|
|
14
|
-
].freeze
|
|
15
|
-
|
|
16
|
-
def install
|
|
17
|
-
css_file = entry_css_file
|
|
18
|
-
return warn_entry_css_not_found unless css_file
|
|
19
|
-
|
|
20
|
-
apply_edit(css_file)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
def warn_entry_css_not_found
|
|
26
|
-
tried = CSS_CANDIDATES.map { |c| File.join(destination_root, c) }
|
|
27
|
-
tried.unshift(File.expand_path(ENV[TAILWIND_CSS_FILE])) if ENV[TAILWIND_CSS_FILE]
|
|
28
|
-
say "Could not find a Tailwind CSS entry file. Tried: #{tried.join(", ")}. " \
|
|
29
|
-
"Set #{TAILWIND_CSS_FILE}=/path/to/entry.css and re-run.",
|
|
30
|
-
:red
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def apply_edit(css_file)
|
|
34
|
-
content = File.read(css_file)
|
|
35
|
-
new_content, status = content_edit(content, source_directive)
|
|
36
|
-
|
|
37
|
-
if new_content
|
|
38
|
-
File.write(css_file, new_content)
|
|
39
|
-
say_status status, relative_to_destination(css_file), :green
|
|
40
|
-
else
|
|
41
|
-
say_status :identical, relative_to_destination(css_file)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def content_edit(content, source_line)
|
|
46
|
-
if content.include?(source_line)
|
|
47
|
-
nil
|
|
48
|
-
elsif (existing = content.match(%r{@source "[^"]*#{Regexp.escape(GEM_NAME)}[^"]*";}))
|
|
49
|
-
[content.sub(existing[0], source_line), :update]
|
|
50
|
-
elsif (import_line = content.match(%r{@import "tailwindcss"[^;]*;}))
|
|
51
|
-
[content.sub(import_line[0], "#{import_line[0]}\n#{source_line}"), :insert]
|
|
52
|
-
else
|
|
53
|
-
["#{content.rstrip}\n#{source_line}\n", :append]
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def source_directive
|
|
58
|
-
spec = Gem.loaded_specs[GEM_NAME]
|
|
59
|
-
%(@source "#{spec.gem_dir}/lib/**/*.rb";)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def entry_css_file
|
|
63
|
-
if ENV[TAILWIND_CSS_FILE]
|
|
64
|
-
path = File.expand_path(ENV[TAILWIND_CSS_FILE])
|
|
65
|
-
return path if File.exist?(path)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
CSS_CANDIDATES
|
|
69
|
-
.map { |c| File.join(destination_root, c) }
|
|
70
|
-
.find { |f| File.exist?(f) }
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def relative_to_destination(path)
|
|
74
|
-
path.delete_prefix("#{destination_root}/")
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module StimulusPlumbersTailwind
|
|
4
|
-
class Engine < ::Rails::Engine
|
|
5
|
-
initializer "stimulus_plumbers_tailwind.register_theme" do
|
|
6
|
-
StimulusPlumbers.configure do |c|
|
|
7
|
-
c.theme.register(:tailwind, StimulusPlumbers::Themes::TailwindTheme)
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
rake_tasks do
|
|
12
|
-
load File.join(__dir__, "../tasks/stimulus_plumbers_tailwind.rake")
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|