snazzy_ui 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5d9e58dccd42693202eede049d9164d90fa664090b8d6b751cb195561d2e0907
4
+ data.tar.gz: bf9cc243639027de0c29ef1a4963653e6be08ef70ceb7f770ef11ed08bf11058
5
+ SHA512:
6
+ metadata.gz: 15d6953ce227735508245df1b0c5ca5ac8e6901261e765e8db714357ea873d8ab9002c794b0771ff7a8c39a6c0eccd710632ceb543b098ec8562a238aa900e0e
7
+ data.tar.gz: 3bfb82fa19e5a264e692678b5559cac54c4320b4eb4d49261eec5e6330cd20652f278047ec99ca37a78e11fc25d847582fbef015882cadba72f0bb7c97f7ba13
data/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # Snazzy 🎩✨
2
+
3
+ **Make your Rails app Snazzy!**
4
+
5
+ Because life's too short for boring UI components. Snazzy brings the pizzazz your ViewComponents have been craving. It's like a fashion makeover for your Rails app, but with less reality TV drama and more actual functionality.
6
+
7
+ ## What's in the box? 📦
8
+
9
+ Snazzy is a collection of reusable UI components built with the holy trinity of modern Rails:
10
+ - 🎨 **ViewComponent** - Because global partials are so 2010
11
+ - 💅 **TailwindCSS** - Making things pretty without the CSS therapy sessions
12
+ - ⚡ **Hotwired** - JavaScript that sparks joy (and actually works)
13
+ - 🏃‍♂️ **Slim Templates** - Because life's too short for closing tags
14
+
15
+ ## Components Gallery 🎪
16
+
17
+ ### Available Components
18
+
19
+ #### 🏷️ BadgeComponent
20
+ Little badges of honor for your UI. Perfect for status indicators, counts, or just making things look official.
21
+ ```ruby
22
+ = render Snazzy::BadgeComponent.new("New", color: "green", size: "small")
23
+ ```
24
+
25
+ #### 💊 PillComponent
26
+ Like badges, but rounder. Because sometimes you need that smooth, pharmaceutical aesthetic.
27
+ ```ruby
28
+ = render Snazzy::PillComponent.new("42 users", color: "blue", hoverable: true)
29
+ ```
30
+
31
+ #### 💬 TooltipComponent
32
+ Hover hints that actually work. No more cryptic UI elements!
33
+ ```ruby
34
+ = render Snazzy::TooltipComponent.new("I'm helpful text!") do
35
+ = link_to "Hover me!", "#"
36
+ ```
37
+
38
+ #### 📋 CopyButtonComponent
39
+ One-click copying that gives users that satisfying "Copied!" feedback.
40
+ ```ruby
41
+ = render Snazzy::CopyButtonComponent.new("secret-api-key", label: "Copy API Key")
42
+ ```
43
+
44
+ #### 🏷️ TagCloudComponent & ArrayInputComponent
45
+ For when you need tags that users can add and remove. Includes built-in validations!
46
+ ```ruby
47
+ = render Snazzy::ArrayInputComponent.new(tag_labels: ["ruby", "rails", "snazzy"])
48
+ ```
49
+
50
+ ## Installation 🚀
51
+
52
+ Add this line to your application's Gemfile:
53
+
54
+ ```ruby
55
+ gem 'snazzy_ui'
56
+ # or if you're living on the edge with a local copy:
57
+ # gem 'snazzy_ui', path: '../snazzy_ui'
58
+ ```
59
+
60
+ Then execute:
61
+
62
+ ```bash
63
+ $ bundle install
64
+ $ bin/rails snazzy:install
65
+ ```
66
+
67
+ The install task will:
68
+ 1. Copy all the Stimulus controllers to `app/javascript/controllers/snazzy/`
69
+ 2. Add the import to your `app/javascript/controllers/index.js`
70
+ 3. Make your app instantly more snazzy ✨
71
+
72
+ ### JavaScript Dependencies 📦
73
+
74
+ Some components need a little extra JavaScript love:
75
+
76
+ **For TooltipComponent** - Add Popper.js for positioning magic:
77
+ ```bash
78
+ $ yarn add @popperjs/core
79
+ # or
80
+ $ npm install @popperjs/core
81
+ ```
82
+
83
+ ## Usage 🎯
84
+
85
+ ### Basic Usage
86
+
87
+ After installation, all components are available under the `Snazzy::` namespace:
88
+
89
+ ```erb
90
+ <!-- In your views -->
91
+ <%= render Snazzy::BadgeComponent.new("Beta", color: "yellow") %>
92
+ <%= render Snazzy::PillComponent.new("5 items", color: "green", size: "large") %>
93
+
94
+ <!-- With blocks -->
95
+ <%= render Snazzy::TooltipComponent.new("This button deletes everything!") do %>
96
+ <button class="btn-danger">Don't Click Me</button>
97
+ <% end %>
98
+ ```
99
+
100
+ ### Stimulus Controllers
101
+
102
+ All Stimulus controllers are namespaced with `snazzy--` to avoid conflicts:
103
+
104
+ ```html
105
+ <div data-controller="snazzy--tooltip">
106
+ <button data-action="mouseover->snazzy--tooltip#show">
107
+ Hover for tooltip
108
+ </button>
109
+ </div>
110
+ ```
111
+
112
+ ### Styling
113
+
114
+ Components use TailwindCSS classes. Make sure your TailwindCSS configuration includes the snazzy gem's view paths:
115
+
116
+ ```javascript
117
+ // tailwind.config.js
118
+ module.exports = {
119
+ content: [
120
+ // ... your other paths
121
+ './node_modules/snazzy/app/components/**/*.{erb,html,slim}',
122
+ ],
123
+ // ... rest of config
124
+ }
125
+ ```
126
+
127
+ ## Component Options 🎛️
128
+
129
+ ### BadgeComponent & PillComponent
130
+ - `text` (required) - The content to display
131
+ - `color` - Color variant (e.g., "red", "green", "blue")
132
+ - `size` - Size variant ("small", "medium", "large")
133
+ - `hoverable` - Boolean for hover effects
134
+ - `iff` - Conditional rendering (defaults to true)
135
+
136
+ ### TooltipComponent
137
+ - `text` (required) - The tooltip content
138
+ - Uses Popper.js for smart positioning
139
+
140
+ ### CopyButtonComponent
141
+ - `copyable` (required) - The text to copy
142
+ - `label` - Button text (default: "Copy")
143
+ - `tooltip` - Optional tooltip text
144
+ - `icon` - Icon path (default: "icons/clipboard.svg")
145
+ - `css_classes` - Additional CSS classes
146
+
147
+ ## Development 🛠️
148
+
149
+ After checking out the repo:
150
+
151
+ ```bash
152
+ $ bin/setup # Install dependencies
153
+ $ bundle exec rspec # Run the tests
154
+ $ bin/console # Interactive prompt for experimentation
155
+ ```
156
+
157
+ To install this gem onto your local machine:
158
+
159
+ ```bash
160
+ $ bundle exec rake install
161
+ ```
162
+
163
+ ## Contributing 🤝
164
+
165
+ Found a bug? Want to add a sparkly new component? Pull requests are welcome!
166
+
167
+ 1. Fork it
168
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
169
+ 3. Make it snazzy
170
+ 4. Commit your changes (`git commit -am 'Add some snazziness'`)
171
+ 5. Push to the branch (`git push origin my-new-feature`)
172
+ 6. Create a new Pull Request
173
+
174
+ ## Why "Snazzy"? 🤔
175
+
176
+ Because naming things is hard, and "AnotherUIComponentGem" was taken. Plus, who doesn't want their app to be snazzy? It's fun to say, easy to type, and makes your README 23% more entertaining.
177
+
178
+ ## License 📄
179
+
180
+ MIT License © 2024-Present Dan Brown
181
+
182
+ In other words: Use it, love it, make it even more snazzy. Just don't blame us if your app becomes too stylish for its own good.
183
+
184
+ ---
185
+
186
+ *Remember: A snazzy app is a happy app!* ✨
@@ -0,0 +1,19 @@
1
+ - name = "#{@model_name}[#{@field}][]"
2
+
3
+ .input-group data-controller="snazzy--tags" data-snazzy--tags-validations-value=@validations
4
+ label = @label_text
5
+ input placeholder=@placeholder data-snazzy--tags-target="input" data-deletable-name=name name=name data-action="keydown->snazzy--tags#handleInput"
6
+ .mt-2
7
+ = "Press "
8
+ code.bg-gray-100.text-red-500.px-2.py-1.border.border-solid.border-gray-500.rounded-md Enter
9
+ = " or "
10
+ code.bg-gray-100.text-red-500.px-2.py-1.border.border-solid.border-gray-500.rounded-md return
11
+ = " after each #{@field.to_s.singularize}."
12
+ .border.border-solid.border-red-300.bg-red-50.text-red-500.px-2.py-1.mt-2.hidden data-snazzy--tags-target="errorContainer"
13
+ .input-wrapper.relative.mt-1
14
+ .TagCloud.inline-flex.flex-wrap.items-center data-snazzy--tags-target="tagCloud"
15
+ - @object.send(@field).each do |lab|
16
+ = render(Snazzy::Tags::GreyTagComponent.new(lab, deletable_name: name))
17
+ div data-snazzy--tags-target="hiddenInputContainer"
18
+ - @object.send(@field).each do |value|
19
+ = @form.hidden_field @field.to_sym, value: value, name:, id: nil
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ class ArrayInputComponent < BaseComponent
5
+ delegate :singularize, to: :helpers
6
+
7
+ def initialize(object:, form:, field:, label_text:, placeholder: "Add a tag...", validations: [])
8
+ @object = object
9
+ @model_name = object.class.name.underscore
10
+ @form = form
11
+ @field = field
12
+ @label_text = label_text
13
+ @placeholder = placeholder
14
+ @validations = validations
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ class BadgeComponent < BaseComponent
5
+ def initialize(text, color: "", hoverable: false, size: nil, iff: true)
6
+ @text = text
7
+ @color = color
8
+ @extra_classes = extra_classes(color, size, hoverable)
9
+ @iff = iff
10
+ end
11
+
12
+ def extra_classes(color, size, hoverable)
13
+ extra_classes = []
14
+
15
+ extra_classes << color if color
16
+ extra_classes << "--#{size}" if size
17
+ extra_classes << "--hoverable" if hoverable
18
+ extra_classes.join(" ")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ - if @iff
2
+ .Badge class=@extra_classes
3
+ = @text
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require "view_component"
3
+
4
+ module Snazzy
5
+ class BaseComponent < ViewComponent::Base
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ class CopyButtonComponent < BaseComponent
5
+ def initialize(copyable, label: "Copy", tooltip: nil, icon: "icons/clipboard.svg", css_classes: "")
6
+ @copyable = copyable
7
+ @label = label
8
+ @tooltip = tooltip
9
+ @icon = icon
10
+ @css_classes = css_classes
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ - if @tooltip
2
+ = render Snazzy::TooltipComponent.new(@tooltip) do
3
+ = link_to "", data: { action: "snazzy--clipboard#oneTimeCopy", content: @copyable }, class: "inline-block p-2 hover:bg-yellow-100 rounded-full transition-colors duration-150 #{@css_classes}" do
4
+ - if respond_to?(:inline_svg_tag)
5
+ = inline_svg_tag @icon, class: "pointer-events-none"
6
+ - else
7
+ span.pointer-events-none = @icon
8
+ - else
9
+ button.inline-block.ml-2.bg-primary-100.px-2.py-1.rounded-md.hover:bg-primary-300.text-white data-action="snazzy--clipboard#oneTimeCopy" data-content=@copyable
10
+ = @label
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ class PillComponent < BaseComponent
5
+ def initialize(text, color: nil, hoverable: false, size: nil, iff: true)
6
+ @text = text
7
+ @extra_classes = extra_classes(color, size, hoverable)
8
+ @iff = iff
9
+ end
10
+
11
+ def extra_classes(color, size, hoverable)
12
+ extra_classes = []
13
+
14
+ extra_classes << color if color
15
+ extra_classes << "--#{size}" if size
16
+ extra_classes << "--hoverable" if hoverable
17
+ extra_classes.join(" ")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ - if @iff
2
+ .Pill class=@extra_classes
3
+ = @text
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ class TagCloudComponent < BaseComponent
5
+ def initialize(tag_labels:)
6
+ @tag_labels = tag_labels
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ .TagCloud.inline-flex.flex-wrap.items-center
2
+ - @tag_labels.each do |lab|
3
+ = render(Snazzy::Tags::GreyTagComponent.new(lab))
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ class Tags::GreyTagComponent < BaseComponent
5
+ def initialize(label, deletable_name: nil)
6
+ @label = label
7
+ @deletable_name = deletable_name
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ span.inline-flex.items-center.rounded-md.bg-gray-50.px-2.py-1.text-xs.font-medium.text-gray-700.ring-1.ring-inset.ring-gray-600/20.mr-2.my-1
2
+ = @label
3
+ - if @deletable_name
4
+ span.ml-2.cursor-pointer data-action="click->snazzy--tags#removeTag" data-deletable-name=@deletable_name X
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ class TooltipComponent < BaseComponent
5
+ def initialize(text)
6
+ @text = text
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ div data-controller="snazzy--tooltip"
2
+ div data-action="mouseover->snazzy--tooltip#show mouseout->snazzy--tooltip#hide" data-snazzy--tooltip-target="source"
3
+ = content
4
+ .tooltip-content.hidden data-snazzy--tooltip-target="content"
5
+ = @text
@@ -0,0 +1,20 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class SnazzyClipboardController extends Controller {
4
+ static targets = [ "source" ]
5
+
6
+ oneTimeCopy() {
7
+ event.preventDefault()
8
+ navigator.clipboard.writeText(event.target.dataset.content)
9
+ event.target.style.cursor = "default"
10
+ event.target.removeAttribute("data-action")
11
+ event.target.classList.add("pointer-events-none")
12
+ event.target.classList.remove("bg-primary-100", "hover:bg-primary-300")
13
+ if (event.target.innerText.length > 0) {
14
+ event.target.innerText = "Copied!"
15
+ event.target.classList.add("bg-emerald-400")
16
+ } else {
17
+ event.target.innerHTML = "✔"
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,10 @@
1
+ import { application } from "../application"
2
+
3
+ import SnazzyTagsController from "./tags_controller"
4
+ import SnazzyTooltipController from "./tooltip_controller"
5
+ import SnazzyClipboardController from "./clipboard_controller"
6
+
7
+ application.register("snazzy--tags", SnazzyTagsController)
8
+ application.register("snazzy--tooltip", SnazzyTooltipController)
9
+ application.register("snazzy--clipboard", SnazzyClipboardController)
10
+
@@ -0,0 +1,134 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class SnazzyTagsController extends Controller {
4
+ static targets = ["input", "tagCloud", "errorContainer", "hiddenInputContainer"];
5
+ static values = {
6
+ validations: Array
7
+ }
8
+
9
+ handleInput(event) {
10
+ if (event.key === 'Enter') {
11
+ event.preventDefault();
12
+ let errors = this.performValidations()
13
+ if (errors.length === 0) {
14
+ this.hideErrorsContainer()
15
+ this.addTag();
16
+ } else {
17
+ this.displayErrors(errors)
18
+ }
19
+ }
20
+ }
21
+
22
+ hideErrorsContainer() {
23
+ this.errorContainerTarget.innerHTML = ""
24
+ this.errorContainerTarget.classList.add("hidden")
25
+ }
26
+
27
+ performValidations() {
28
+ let errors = []
29
+ this.validationsValue.forEach((validationName) => {
30
+ let error = this.callValidation(validationName);
31
+ if (error) {
32
+ errors.push(error);
33
+ }
34
+ })
35
+
36
+ return errors
37
+ }
38
+
39
+ callValidation(validationName) {
40
+ const validationHandler = 'validate' + validationName.charAt(0).toUpperCase() + validationName.slice(1);
41
+ const value = this.inputTarget.value;
42
+ if (typeof this[validationHandler] === 'function') {
43
+ return this[validationHandler](value);
44
+ } else {
45
+ console.error(`${validationHandler} does not exist`);
46
+ }
47
+ }
48
+
49
+ validateEmail(value) {
50
+ const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
51
+ if (!emailPattern.test(value)) {
52
+ return `${value} is not a valid email address.`
53
+ }
54
+ }
55
+
56
+ validateUniqueness(value) {
57
+ const inputs = this.hiddenInputContainerTarget.querySelectorAll("input")
58
+ const duplicateFound = Array.from(inputs).some(i => i.value == value)
59
+
60
+ if(duplicateFound) {
61
+ this.inputTarget.value = ""
62
+ return `${value} is already in the list.`
63
+ }
64
+ }
65
+
66
+ displayErrors(errors) {
67
+ this.errorContainerTarget.innerHTML = ""
68
+ errors.forEach((error) => {
69
+ let li = document.createElement('li');
70
+ li.textContent = error;
71
+ this.errorContainerTarget.appendChild(li);
72
+ this.errorContainerTarget.classList.remove("hidden")
73
+ })
74
+ }
75
+
76
+ addTag() {
77
+ const value = this.inputTarget.value.trim();
78
+
79
+ if (value) {
80
+ const tagElement = this.generateTagElement(value, this.inputTarget.dataset.deletableName);
81
+ this.tagCloudTarget.append(tagElement);
82
+ this.addHiddenInput(value)
83
+ this.inputTarget.value = "";
84
+ this.inputTarget.focus();
85
+ }
86
+ }
87
+
88
+ removeTag(event) {
89
+ let parent = event.currentTarget.parentElement
90
+ let obsoleteValue = parent.innerHTML.split("<span")[0]
91
+ let obsoleteInput = document.querySelector("input[name='" + event.currentTarget.dataset.deletableName + "'][value='" + obsoleteValue + "']")
92
+ parent.remove();
93
+ obsoleteInput.remove();
94
+
95
+ this.handleLastTagRemoval();
96
+ }
97
+
98
+ addHiddenInput(value) {
99
+ const hiddenInput = document.createElement("input")
100
+ hiddenInput.name = this.inputTarget.dataset.deletableName
101
+ hiddenInput.autocomplete = "off"
102
+ hiddenInput.type = "hidden"
103
+ hiddenInput.value = value
104
+ this.hiddenInputContainerTarget.appendChild(hiddenInput)
105
+ }
106
+
107
+ handleLastTagRemoval() {
108
+ if (this.tagCloudTarget.children.length === 0) {
109
+ this.addEmptyHiddenInput();
110
+ }
111
+ }
112
+
113
+ addEmptyHiddenInput() {
114
+ const hiddenInput = document.createElement("input");
115
+ hiddenInput.name = this.inputTarget.dataset.deletableName;
116
+ hiddenInput.type = "hidden";
117
+ this.hiddenInputContainerTarget.appendChild(hiddenInput);
118
+ }
119
+
120
+ generateTagElement(content, deletableName) {
121
+ const tag = document.createElement("span");
122
+ tag.className = "inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-700 ring-1 ring-inset ring-gray-600/20 mr-2 my-1";
123
+ tag.textContent = content;
124
+
125
+ const closeButton = document.createElement("span");
126
+ closeButton.dataset.action = "click->snazzy--tags#removeTag"
127
+ closeButton.classList.add("ml-2", "cursor-pointer")
128
+ closeButton.dataset.deletableName = deletableName
129
+ closeButton.textContent = "X";
130
+
131
+ tag.appendChild(closeButton);
132
+ return tag;
133
+ }
134
+ }
@@ -0,0 +1,44 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { createPopper } from "@popperjs/core"
3
+
4
+ export default class SnazzyTooltipController extends Controller {
5
+ static targets = ["source", "content"]
6
+
7
+ connect() {
8
+ this.popper = createPopper(this.sourceTarget, this.contentTarget, {
9
+ placement: 'top',
10
+ modifiers: [
11
+ {
12
+ name: 'flip',
13
+ options: {
14
+ fallbackPlacements: ['bottom'],
15
+ },
16
+ },
17
+ {
18
+ name: 'preventOverflow',
19
+ options: {
20
+ padding: 8,
21
+ },
22
+ },
23
+ {
24
+ name: 'offset',
25
+ options: {
26
+ offset: [0, 8],
27
+ },
28
+ },
29
+ ],
30
+ });
31
+
32
+ this.contentTarget.classList.add('hidden');
33
+ }
34
+
35
+ show() {
36
+ this.contentTarget.classList.remove('hidden');
37
+ this.popper.update();
38
+ }
39
+
40
+ hide() {
41
+ clearTimeout(this.timeout);
42
+ this.contentTarget.classList.add('hidden');
43
+ }
44
+ }
@@ -0,0 +1,8 @@
1
+ require "rails"
2
+ require "view_component/engine"
3
+
4
+ module Snazzy
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace Snazzy
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Snazzy
4
+ VERSION = "0.1.0"
5
+ end
data/lib/snazzy_ui.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "snazzy/version"
4
+ require "snazzy/engine"
5
+
6
+ module Snazzy
7
+ end
@@ -0,0 +1,28 @@
1
+ namespace :snazzy do
2
+ desc "Install Snazzy JavaScript controllers into the Rails application"
3
+ task install: :environment do
4
+ require "fileutils"
5
+
6
+ gem_path = File.expand_path("../..", __dir__)
7
+ stimulus_controllers_dest = "app/javascript/controllers/snazzy"
8
+ source_path = File.join(gem_path, stimulus_controllers_dest)
9
+ dest_path = Rails.root.join(stimulus_controllers_dest)
10
+ FileUtils.mkdir_p(dest_path) unless File.directory?(dest_path)
11
+ FileUtils.cp_r("#{source_path}/.", dest_path)
12
+ puts "Snazzy controllers have been installed successfully."
13
+
14
+ parent_js_path = "app/javascript/controllers/index.js"
15
+
16
+ content = File.readlines(parent_js_path)
17
+
18
+ if content.any? { |line| line.strip == 'import "./snazzy"' }
19
+ puts 'The line "import "./snazzy"" is already present in the file.'
20
+ else
21
+ File.open(parent_js_path, "a") do |file|
22
+ file.puts 'import "./snazzy"'
23
+ end
24
+
25
+ puts "Updated the index.js file successfully."
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snazzy_ui
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dan Brown
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-07-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slim-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.6'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 3.6.3
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '3.6'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 3.6.3
47
+ - !ruby/object:Gem::Dependency
48
+ name: view_component
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.10'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 3.10.0
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '3.10'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 3.10.0
67
+ description: Snazzy provides a suite of stylish, reusable UI components for Ruby on
68
+ Rails applications that leverage GitHub's ViewComponents, TailwindCSS and Rails.
69
+ email:
70
+ - dbrown@occameducation.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - README.md
76
+ - app/components/snazzy/array_input_component.html.slim
77
+ - app/components/snazzy/array_input_component.rb
78
+ - app/components/snazzy/badge_component.rb
79
+ - app/components/snazzy/badge_component.slim
80
+ - app/components/snazzy/base_component.rb
81
+ - app/components/snazzy/copy_button_component.rb
82
+ - app/components/snazzy/copy_button_component.slim
83
+ - app/components/snazzy/pill_component.rb
84
+ - app/components/snazzy/pill_component.slim
85
+ - app/components/snazzy/tag_cloud_component.rb
86
+ - app/components/snazzy/tag_cloud_component.slim
87
+ - app/components/snazzy/tags/grey_tag_component.rb
88
+ - app/components/snazzy/tags/grey_tag_component.slim
89
+ - app/components/snazzy/tooltip_component.rb
90
+ - app/components/snazzy/tooltip_component.slim
91
+ - app/javascript/controllers/snazzy/clipboard_controller.js
92
+ - app/javascript/controllers/snazzy/index.js
93
+ - app/javascript/controllers/snazzy/tags_controller.js
94
+ - app/javascript/controllers/snazzy/tooltip_controller.js
95
+ - lib/snazzy/engine.rb
96
+ - lib/snazzy/version.rb
97
+ - lib/snazzy_ui.rb
98
+ - lib/tasks/install.rake
99
+ homepage: https://github.com/lordofthedanse/snazzy_ui
100
+ licenses:
101
+ - MIT
102
+ metadata:
103
+ homepage_uri: https://github.com/lordofthedanse/snazzy_ui
104
+ source_code_uri: https://github.com/lordofthedanse/snazzy_ui
105
+ bug_tracker_uri: https://github.com/lordofthedanse/snazzy_ui/issues
106
+ changelog_uri: https://github.com/lordofthedanse/snazzy_ui/blob/main/CHANGELOG.md
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '3.2'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubygems_version: 3.5.22
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: A collection of snazzy UI components for Rails applications.
126
+ test_files: []