hanami_icons 0.5.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: f3afa33bc73c5af3cbd69a0e5fc7a9417c608b6173ea4e1ab0ceb101220af122
4
+ data.tar.gz: 3409501c85d83eee1d8871251d58012f89552b56bd00450918ef62ec0c3bd080
5
+ SHA512:
6
+ metadata.gz: 653d92e5ca0206d4a8ddd09d6b8ea393078e66f4850c8c8b1be4d390daf2cbac44f514c64556b3a54a0ca774b6140554963d7428911e82554aa6d950d2bfd080
7
+ data.tar.gz: f7f93a4158c3817630bb28563267807a66a58cf2c3bf7fd5d2381724f41a0127349f897c8431ee951bdc4b356f9d1b9cd60cde4cd7c5406bafdddde04af9211e
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ gem "minitest"
8
+ gem "rake"
9
+ gem "standard"
data/README.md ADDED
@@ -0,0 +1,228 @@
1
+ # Hanami Icons
2
+
3
+ Add any icon library to a Hanami app. Hanami Icons has first-party support for a [handful of libraries](#first-party-libraries). It is library agnostic so it can be used with any icon library using the same interface. Hanami Icons is a Hanami gem for the [Icons Ruby gem](https://github.com/Rails-Designer/icons).
4
+
5
+ ```erb
6
+ # Using the default icon library
7
+ <%== icon "check", class: "text-gray-500" %>
8
+
9
+ # Using any custom library
10
+ <%== icon "apple", library: "simple_icons", class: "text-black" %>
11
+ ```
12
+
13
+ The icons are sourced directly from their respective GitHub repositories via the [Icons](https://github.com/Rails-Designer/icons) gem, ensuring Hanami Icons remain lightweight.
14
+
15
+ **Sponsored By [Rails Designer](https://railsdesigner.com/)**
16
+
17
+ ## Install
18
+
19
+ Add the gem:
20
+
21
+ ```bash
22
+ bundle add hanami_icons
23
+ ```
24
+
25
+ Install, choosing one of the supported libraries:
26
+
27
+ ```bash
28
+ hanami generate icons --library=heroicons
29
+ ```
30
+
31
+ **Example**
32
+
33
+ ```bash
34
+ hanami generate icons --library=heroicons
35
+
36
+ # Or multiple at once
37
+ hanami generate icons --libraries=heroicons lucide
38
+
39
+ # Or only specific variants
40
+ hanami generate icons --library=heroicons --variants solid outline
41
+ ```
42
+
43
+ This creates `config/providers/icons.rb`, registers the provider with the app container and adds the view helpers into `app/views/helpers.rb`.
44
+
45
+ ## Usage
46
+
47
+ ```ruby
48
+ # Uses the default library and variant defined in config/providers/icons.rb
49
+ icon "check"
50
+
51
+ # Use another variant
52
+ icon "check", variant: "solid"
53
+
54
+ # Set library explicitly
55
+ icon "check", library: "heroicons"
56
+
57
+ # Add CSS
58
+ icon "check", class: "text-green-500"
59
+
60
+ # Add data attributes
61
+ icon "check", data: { controller: "swap" }
62
+
63
+ # Set the stroke-width
64
+ icon "check", stroke_width: 2
65
+
66
+ # Base64-encoded data URI
67
+ encoded_icon "check"
68
+ ```
69
+
70
+ The helpers return `Hanami::View::HTML::SafeString`, so they are safe to output in templates (`<%== … %>` or `&= …`).
71
+
72
+ ## Sprites
73
+
74
+ Hanami Icons supports SVG sprites for improved performance. Instead of inlining each icon's full SVG, sprite icons reference a shared set of `<symbol>` definitions via `<use href="…">`.
75
+
76
+ ### Configuration
77
+
78
+ ```ruby
79
+ # config/providers/icons.rb
80
+ HanamiIcons.configure do |config|
81
+ config.default_library = "heroicons"
82
+ config.default_variant = "outline"
83
+
84
+ # Where `sprite_icon` references symbols. Set to nil to use inline mode (`<%== icons_sprite %>` in layout).
85
+ config.default_sprite_location = "/sprite.svg"
86
+
87
+ # Set to true to validate that referenced icons exist on disk
88
+ config.validate_sprite_icons = false
89
+
90
+ # Define which icons to include in the sprite
91
+ config.sprite = {
92
+ heroicons: {
93
+ outline: %w[check chevron-down menu search x],
94
+ mini: %w[check chevron-down]
95
+ }
96
+ }
97
+ end
98
+ ```
99
+
100
+ ### External sprite
101
+
102
+ Generate a static sprite file and reference it with `sprite_icon`:
103
+
104
+ ```bash
105
+ hanami generate icons:sprite
106
+ ```
107
+
108
+ ```erb
109
+ <%== sprite_icon "check" %>
110
+ <%# renders: <svg><use href="/sprite.svg#heroicons_outline_check"></use></svg> %>
111
+ ```
112
+
113
+ Point at a precompiled file or a CDN by changing the location:
114
+
115
+ ```ruby
116
+ config.default_sprite_location = "https://cdn.example.com/sprite_icons.svg"
117
+ ```
118
+
119
+ Override per icon:
120
+
121
+ ```erb
122
+ <%== sprite_icon "check", sprite_location: "/assets/sprites.svg" %>
123
+ ```
124
+
125
+ ### Inline sprite
126
+
127
+ Set the location to `nil` and embed the sprite directly in your layout:
128
+
129
+ ```ruby
130
+ config.default_sprite_location = nil
131
+ ```
132
+
133
+ ```erb
134
+ <body>
135
+ <%== icons_sprite %>
136
+
137
+ <%== sprite_icon "check" %>
138
+ <%== sprite_icon "search", class: "text-blue-500" %>
139
+ <%== sprite_icon "menu", data: { controller: "nav" } %>
140
+ </body>
141
+ ```
142
+
143
+ You can also generate a sprite for a specific set of icons:
144
+
145
+ ```erb
146
+ <%== icons_sprite ["check", "search"], library: "heroicons", variant: "outline" %>
147
+ ```
148
+
149
+ ## Sync icons
150
+
151
+ To sync all libraries, run:
152
+
153
+ ```bash
154
+ hanami generate icons:sync
155
+ ```
156
+
157
+ To sync only a specific library, run:
158
+
159
+ ```bash
160
+ hanami generate icons:sync --library=heroicons
161
+
162
+ # Or multiple at once:
163
+ hanami generate icons:sync --libraries=heroicons lucide
164
+ ```
165
+
166
+ To sync only specific variants for a library:
167
+
168
+ ```bash
169
+ hanami generate icons:sync --library=heroicons --variants solid outline
170
+ ```
171
+
172
+ ## Custom icon libraries
173
+
174
+ Hanami Icons pulls SVGs straight from the path `<icons_path>/<library_name>/<name>.svg`. No generator is required for custom icons. Configuration is optional and only used to define defaults.
175
+
176
+ To add a custom library, create its directory and drop in your SVGs:
177
+
178
+ ```
179
+ app/assets/svg/icons/simple_icons/apple.svg
180
+ ```
181
+
182
+ (alternatively, scaffold it with `hanami generate icons --library=simple_icons`, which creates the directory and adds `config.custom_library :simple_icons` in the provider.)
183
+
184
+ Use them like any other library:
185
+
186
+ ```ruby
187
+ icon "apple", library: "simple_icons"
188
+ ```
189
+
190
+ To add a git source for syncing, edit the provider:
191
+
192
+ ```ruby
193
+ HanamiIcons.configure do |config|
194
+ config.custom_library :my_icons, source: {
195
+ url: "https://github.com/user/icons.git",
196
+ variants: { default: "." }
197
+ }
198
+ end
199
+ ```
200
+
201
+ Then sync:
202
+
203
+ ```bash
204
+ hanami generate icons:sync --library=my_icons
205
+ ```
206
+
207
+ ## First-party libraries
208
+
209
+ - [Boxicons](https://railsdesigner.com/open-source/rails-icons/boxicons/) (1600+ icons)
210
+ - [Feather](https://railsdesigner.com/open-source/rails-icons/feather/) (280+ icons)
211
+ - [Flags](https://railsdesigner.com/open-source/rails-icons/flags/) (540+ icons)
212
+ - [Heroicons](https://railsdesigner.com/open-source/rails-icons/heroicons/) (300+ icons)
213
+ - [Hugeicons](https://railsdesigner.com/open-source/rails-icons/hugeicons/) (4600+ icons)
214
+ - [Linear](https://railsdesigner.com/open-source/rails-icons/linear/) (170+ icons)
215
+ - [Lucide](https://railsdesigner.com/open-source/rails-icons/lucide/) (1500+ icons)
216
+ - [Phosphor](https://railsdesigner.com/open-source/rails-icons/phosphor/) (9000+ icons)
217
+ - [Radix](https://railsdesigner.com/open-source/rails-icons/radix/) (300+ icons)
218
+ - [SidekickIcons](https://railsdesigner.com/open-source/rails-icons/sidekickicons/) (49 icons, complementing [Heroicons](https://railsdesigner.com/open-source/rails-icons/heroicons/))
219
+ - [Tabler](https://railsdesigner.com/open-source/rails-icons/tabler/) (5700+ icons)
220
+ - [Weather](https://railsdesigner.com/open-source/rails-icons/weather/) (215+ icons)
221
+
222
+ ## Contributing
223
+
224
+ This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `bundle exec standardrb` before submitting pull requests. Run tests via `bundle exec rake`.
225
+
226
+ ## License
227
+
228
+ Hanami Icons is released under the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+
10
+ t.test_files = FileList["test/**/*_test.rb"]
11
+ end
12
+
13
+ task :standard do
14
+ sh "bundle exec standardrb"
15
+ end
16
+
17
+ task default: %i[test standard]
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/hanami_icons/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "hanami_icons"
7
+ spec.version = HanamiIcons::VERSION
8
+ spec.authors = ["Rails Designer"]
9
+ spec.email = ["devs@railsdesigner.com"]
10
+
11
+ spec.summary = "Add any icon library to a Hanami app"
12
+ spec.description = "Add any icon library to a Hanami app, from Heroicons, to Lucide to Tabler (and others). Hanami Icons is library-agnostic, so you can add any library while using the same interface."
13
+ spec.homepage = "https://railsdesigner.com/open-source/hanami-icons/"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/Rails-Designer/hanami_icons"
18
+ spec.metadata["changelog_uri"] = "https://github.com/Rails-Designer/hanami_icons/releases"
19
+ spec.metadata["bug_tracker_uri"] = "https://github.com/Rails-Designer/hanami_icons/issues"
20
+ spec.metadata["documentation_uri"] = spec.homepage
21
+ spec.metadata["rubygems_mfa_required"] = "true"
22
+
23
+ spec.files = Dir["lib/**/*", "Rakefile", "README.md", "LICENSE.txt", "hanami_icons.gemspec", "Gemfile"]
24
+
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.required_ruby_version = ">= 3.3"
28
+
29
+ spec.add_dependency "base64"
30
+ spec.add_dependency "hanami-view", "~> 3.0"
31
+ spec.add_dependency "hanami-cli", "~> 3.0"
32
+ spec.add_dependency "icons", "~> 0.11.0"
33
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/cli"
4
+
5
+ module HanamiIcons
6
+ module CLI
7
+ module Commands
8
+ module Generate
9
+ # Installs Hanami Icons by creating the provider file, wiring the view
10
+ # helpers and syncing the chosen libraries.
11
+ #
12
+ # @api public
13
+ # @since 0.1.0
14
+ class Icons < Hanami::CLI::Command
15
+ desc "Install Hanami Icons with the chosen libraries"
16
+
17
+ option :library, desc: "Choose a library"
18
+ option :libraries, type: :array, default: [], desc: "Choose libraries"
19
+ option :variants, type: :array, desc: "Only sync specific variants (e.g. solid outline)"
20
+ option :destination, type: :string, default: HanamiIcons.configuration.icons_path, desc: "Specify destination folder for icons"
21
+ option :skip_sync, type: :boolean, default: false
22
+
23
+ # @param library [String, nil]
24
+ # @param libraries [Array<String>]
25
+ # @param variants [Array<String>, nil]
26
+ # @param destination [String]
27
+ # @param skip_sync [Boolean]
28
+ #
29
+ # @api public
30
+ # @since 0.1.0
31
+ def call(library: nil, libraries: [], variants: nil, destination: HanamiIcons.configuration.icons_path, skip_sync: false, **)
32
+ run_initializer(library: library, libraries: libraries, variants: variants, destination: destination)
33
+
34
+ if !skip_sync && selected_libraries(library, libraries).any?
35
+ run_sync(library: library, libraries: libraries, variants: variants)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @api private
42
+ # @since 0.1.0
43
+ def run_initializer(library:, libraries:, variants:, destination:)
44
+ Generate::Initializer.new(out: out, err: err, fs: fs).call(
45
+ library: library,
46
+ libraries: libraries,
47
+ variants: variants,
48
+ destination: destination
49
+ )
50
+ end
51
+
52
+ # @api private
53
+ # @since 0.1.0
54
+ def run_sync(library:, libraries:, variants:)
55
+ Generate::Sync.new(out: out, err: err, fs: fs).call(
56
+ library: library,
57
+ libraries: libraries,
58
+ variants: variants
59
+ )
60
+ end
61
+
62
+ # @api private
63
+ # @since 0.1.0
64
+ def selected_libraries(library, libraries)
65
+ [library, *libraries].compact.reject(&:empty?).map(&:downcase).uniq
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/cli"
4
+
5
+ module HanamiIcons
6
+ module CLI
7
+ module Commands
8
+ module Generate
9
+ # Creates the Hanami Icons provider file (`config/providers/icons.rb`),
10
+ # which Hanami auto-loads, and registers the view helpers in the app's
11
+ # helpers module (`app/views/helpers.rb`).
12
+ #
13
+ # @api public
14
+ # @since 0.1.0
15
+ class Initializer < Hanami::CLI::Command
16
+ desc "Create the Hanami Icons provider file"
17
+
18
+ option :library, desc: "Choose a library"
19
+ option :libraries, type: :array, default: [], desc: "Choose libraries"
20
+ option :variants, type: :array, desc: "Only sync specific variants (e.g. solid outline)"
21
+ option :destination, type: :string, default: HanamiIcons.configuration.icons_path, desc: "Specify destination folder for icons"
22
+
23
+ PROVIDER = "config/providers/icons.rb"
24
+ HELPERS = "app/views/helpers.rb"
25
+ TEMPLATE = File.expand_path("../../templates/provider.rb", __dir__)
26
+
27
+ # @param library [String, nil]
28
+ # @param libraries [Array<String>]
29
+ # @param variants [Array<String>, nil]
30
+ # @param destination [String]
31
+ #
32
+ # @api public
33
+ # @since 0.1.0
34
+ def call(library: nil, libraries: [], variants: nil, destination: HanamiIcons.configuration.icons_path, **)
35
+ copy_provider
36
+
37
+ insert_default_configuration(selected_libraries(library, libraries).first)
38
+ insert_icons_path(destination)
39
+ setup_custom_libraries(selected_libraries(library, libraries), destination)
40
+
41
+ register_helpers
42
+ end
43
+
44
+ private
45
+
46
+ # @api private
47
+ # @since 0.1.0
48
+ def copy_provider
49
+ return if fs.exist?(PROVIDER)
50
+
51
+ fs.mkdir(File.dirname(PROVIDER))
52
+ fs.write(PROVIDER, File.read(TEMPLATE))
53
+ end
54
+
55
+ # @api private
56
+ # @since 0.1.0
57
+ def insert_default_configuration(library)
58
+ return if library.nil? || default_configuration_exists?
59
+
60
+ insert_into_provider(
61
+ indent("config.default_library = \"#{library}\"\n", 2),
62
+ after: "HanamiIcons.configure do |config|\n"
63
+ )
64
+ end
65
+
66
+ # @api private
67
+ # @since 0.1.0
68
+ def insert_icons_path(destination)
69
+ return if destination == HanamiIcons.configuration.icons_path
70
+ return if icons_path_exists?
71
+
72
+ insert_into_provider(
73
+ indent("# Default icons path\nconfig.icons_path = \"#{destination}\"\n", 2),
74
+ after: "HanamiIcons.configure do |config|\n"
75
+ )
76
+ end
77
+
78
+ # @api private
79
+ # @since 0.1.0
80
+ def setup_custom_libraries(libraries, destination)
81
+ custom_libraries(libraries).each do |name|
82
+ fs.mkdir(File.join(destination, name))
83
+
84
+ insert_into_provider(
85
+ "\n#{indent("config.custom_library :#{name}", 2)}",
86
+ before: "end"
87
+ )
88
+ end
89
+ end
90
+
91
+ # @api private
92
+ # @since 0.1.0
93
+ def register_helpers
94
+ unless fs.exist?(HELPERS)
95
+ warn "[HanamiIcons] Could not find #{HELPERS}. Add `include HanamiIcons::Helpers::IconHelper` and `include HanamiIcons::Helpers::SpriteHelper` to your app's Views::Helpers module manually."
96
+
97
+ return
98
+ end
99
+
100
+ content = fs.read(HELPERS)
101
+
102
+ return if content.include?("include HanamiIcons::Helpers::IconHelper")
103
+
104
+ line = content.lines.find { it.match?(/^\s*module\s+Helpers\b/) }
105
+
106
+ unless line
107
+ warn "[HanamiIcons] Could not find a `module Helpers` in #{HELPERS}. Add the helper includes manually."
108
+
109
+ return
110
+ end
111
+
112
+ indentation = line[/^\s*/]
113
+ includes = "\n#{indentation} include HanamiIcons::Helpers::IconHelper\n#{indentation} include HanamiIcons::Helpers::SpriteHelper"
114
+
115
+ fs.write(HELPERS, content.sub(/^(\s*module\s+Helpers\b.*)$/, "\\1#{includes}"))
116
+ end
117
+
118
+ # @api private
119
+ # @since 0.1.0
120
+ def insert_into_provider(content, after: nil, before: nil)
121
+ text = fs.read(PROVIDER)
122
+
123
+ if after
124
+ text = text.sub(after, "#{after}#{content}")
125
+ elsif before
126
+ text = text.sub(before, "#{content}\n#{before}")
127
+ end
128
+
129
+ fs.write(PROVIDER, text)
130
+ end
131
+
132
+ # @api private
133
+ # @since 0.1.0
134
+ def default_configuration_exists?
135
+ line = /^\s*config\.default_library\s*=/
136
+
137
+ fs.read(PROVIDER).lines.any? { it.match?(line) }
138
+ end
139
+
140
+ # @api private
141
+ # @since 0.1.0
142
+ def icons_path_exists?
143
+ line = /^\s*config\.icons_path\s*=/
144
+
145
+ fs.read(PROVIDER).lines.any? { it.match?(line) }
146
+ end
147
+
148
+ # @api private
149
+ # @since 0.1.0
150
+ def custom_libraries(libraries)
151
+ libraries.reject { HanamiIcons.libraries.key?(it.to_sym) }
152
+ end
153
+
154
+ # @api private
155
+ # @since 0.1.0
156
+ def selected_libraries(library, libraries)
157
+ [library, *libraries].compact.reject(&:empty?).map(&:downcase).uniq
158
+ end
159
+
160
+ # @api private
161
+ # @since 0.1.0
162
+ def indent(text, spaces)
163
+ prefix = " " * spaces
164
+
165
+ text.lines.map { "#{prefix}#{it}" }.join
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/cli"
4
+
5
+ module HanamiIcons
6
+ module CLI
7
+ module Commands
8
+ module Generate
9
+ # Writes a static SVG sprite file for use with `sprite_icon`.
10
+ #
11
+ # @api public
12
+ # @since 0.1.0
13
+ class Sprite < Hanami::CLI::Command
14
+ desc "Generate a static SVG sprite file"
15
+
16
+ option :output, type: :string, default: "public/sprite.svg", desc: "Where to write the sprite file"
17
+
18
+ # @param output [String]
19
+ #
20
+ # @api public
21
+ # @since 0.1.0
22
+ def call(output: "public/sprite.svg", **)
23
+ fs.mkdir(File.dirname(output))
24
+ fs.write(output, ::Icons::Sprite.new.svg)
25
+
26
+ location = "/#{File.basename(output)}"
27
+
28
+ out.puts "Sprite written to #{output}"
29
+ out.puts "Set config.default_sprite_location = \"#{location}\" in config/providers/icons.rb to use it."
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/cli"
4
+
5
+ module HanamiIcons
6
+ module CLI
7
+ module Commands
8
+ module Generate
9
+ # Syncs the chosen icon libraries from their respective git repositories.
10
+ #
11
+ # @api public
12
+ # @since 0.1.0
13
+ class Sync < Hanami::CLI::Command
14
+ desc "Sync the chosen icon libraries from their respective git repos"
15
+
16
+ option :library, desc: "Choose a library"
17
+ option :libraries, type: :array, default: [], desc: "Choose libraries"
18
+ option :variants, type: :array, desc: "Only sync specific variants (e.g. solid outline)"
19
+
20
+ # @param library [String, nil]
21
+ # @param libraries [Array<String>]
22
+ # @param variants [Array<String>, nil]
23
+ #
24
+ # @api public
25
+ # @since 0.1.0
26
+ def call(library: nil, libraries: [], variants: nil, **)
27
+ selected_libraries(library, libraries).each do |name|
28
+ ::Icons::Sync.new(name, variants: variants&.map(&:to_sym)).now
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # @api private
35
+ # @since 0.1.0
36
+ def selected_libraries(library, libraries)
37
+ [library, *libraries].compact.reject(&:empty?).map(&:downcase).uniq
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami_icons"
4
+
5
+ HanamiIcons.configure do |config|
6
+ end
7
+
8
+ Hanami.app.register_provider(:icons) do
9
+ start do
10
+ register "icons", HanamiIcons
11
+ end
12
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+
5
+ module HanamiIcons
6
+ module Helpers
7
+ # View helpers for rendering inline SVG icons.
8
+ #
9
+ # @api public
10
+ # @since 0.1.0
11
+ module IconHelper
12
+ extend self
13
+
14
+ # Renders an SVG icon.
15
+ #
16
+ # @param name [String] The icon name
17
+ # @param library [String] The icon library (defaults to HanamiIcons configuration)
18
+ # @param from [String] Syntactic sugar for a cleanly readable view layer API
19
+ # @param variant [String] The icon variant (optional)
20
+ # @param arguments [Hash] Additional attributes including class, data, stroke_width, etc.
21
+ # @return [Hanami::View::HTML::SafeString] An HTML-safe SVG string
22
+ #
23
+ # @example
24
+ # <%= icon "chevron-down" %>
25
+ # <%= icon "search", class: "text-blue-500" %>
26
+ #
27
+ # @api public
28
+ # @since 0.1.0
29
+ def icon(name, library: HanamiIcons.configuration.default_library, from: library, variant: nil, **arguments)
30
+ Icons::Icon.new(
31
+ name: name,
32
+ library: from || library,
33
+ variant: variant,
34
+ arguments: arguments
35
+ ).svg.html_safe
36
+ end
37
+
38
+ # Returns a base64-encoded data URI for an icon.
39
+ #
40
+ # @param name [String] The icon name
41
+ # @param library [String] The icon library (defaults to HanamiIcons configuration)
42
+ # @param from [String] Syntactic sugar for a cleanly readable view layer API
43
+ # @param variant [String] The icon variant (optional)
44
+ # @param arguments [Hash] Additional attributes including class, data, stroke_width, etc.
45
+ # @return [String] A base64-encoded data URI (e.g. "data:image/svg+xml;base64,...")
46
+ #
47
+ # @example
48
+ # <%= encoded_icon "chevron-down" %>
49
+ #
50
+ # @api public
51
+ # @since 0.1.0
52
+ def encoded_icon(name, library: HanamiIcons.configuration.default_library, from: library, variant: nil, **arguments)
53
+ svg = Icons::Icon.new(
54
+ name: name,
55
+ library: from || library,
56
+ variant: variant,
57
+ arguments: arguments
58
+ ).svg
59
+
60
+ "data:image/svg+xml;base64,#{Base64.strict_encode64(svg)}"
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "icons/sprite_icon"
4
+
5
+ module HanamiIcons
6
+ module Helpers
7
+ # View helpers for rendering SVG icons from a sprite.
8
+ #
9
+ # @api public
10
+ # @since 0.1.0
11
+ module SpriteHelper
12
+ extend self
13
+
14
+ # Renders an SVG icon referencing a sprite symbol.
15
+ #
16
+ # @param name [String] The icon name
17
+ # @param library [String] The icon library (defaults to HanamiIcons configuration)
18
+ # @param from [String] Syntactic sugar for a cleanly readable view layer API
19
+ # @param variant [String] The icon variant (optional)
20
+ # @param sprite_location [String] Override URL for the sprite file (optional)
21
+ # @param arguments [Hash] Additional attributes including class, data, stroke_width, etc.
22
+ # @return [Hanami::View::HTML::SafeString] An HTML-safe SVG string
23
+ #
24
+ # @example
25
+ # <%= sprite_icon "chevron-down" %>
26
+ # <%= sprite_icon "check", sprite_location: "/sprite.svg" %>
27
+ #
28
+ # @api public
29
+ # @since 0.1.0
30
+ def sprite_icon(name, library: nil, from: library, variant: nil, sprite_location: nil, **arguments)
31
+ Icons::SpriteIcon.new(
32
+ name: name,
33
+ library: from || library || HanamiIcons.configuration.default_library,
34
+ variant: variant,
35
+ sprite_location: sprite_location,
36
+ arguments: arguments
37
+ ).svg.html_safe
38
+ end
39
+
40
+ # Returns the inline SVG sprite containing all symbols.
41
+ #
42
+ # @param icons [Array<String>, nil] Optional list of icon names (defaults to all configured icons)
43
+ # @param library [String, nil] Optional library to use for icons
44
+ # @param variant [String, nil] Optional variant to use for icons
45
+ # @return [Hanami::View::HTML::SafeString] An HTML-safe SVG string
46
+ #
47
+ # @example
48
+ # <%= icons_sprite %>
49
+ # <%= icons_sprite ["check", "search"], library: "lucide" %>
50
+ #
51
+ # @api public
52
+ # @since 0.1.0
53
+ def icons_sprite(icons = nil, library: nil, variant: nil)
54
+ Icons::Sprite.new(icons: icons, library: library, variant: variant).svg.html_safe
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module HanamiIcons
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeitwerk"
4
+ require "icons"
5
+ require "hanami/cli"
6
+
7
+ module HanamiIcons
8
+ # @api private
9
+ # @since 0.1.0
10
+ def self.gem_loader
11
+ @gem_loader ||= Zeitwerk::Loader.new.tap do |loader|
12
+ root = __dir__
13
+
14
+ loader.tag = "hanami-icons"
15
+ loader.inflector = Zeitwerk::GemInflector.new("#{root}/hanami_icons.rb")
16
+ loader.inflector.inflect("cli" => "CLI")
17
+ loader.push_dir(root)
18
+
19
+ loader.ignore("#{root}/hanami_icons.rb", "#{root}/hanami_icons/version.rb")
20
+ end
21
+ end
22
+
23
+ gem_loader.setup
24
+
25
+ require_relative "hanami_icons/version"
26
+
27
+ class << self
28
+ # @yield [config] Yields the Icons configuration
29
+ # @yieldparam config [Icons::Configuration]
30
+ #
31
+ # @api public
32
+ # @since 0.1.0
33
+ def configure(&block) = Icons.configure(&block)
34
+
35
+ # @return [Icons::Configuration]
36
+ #
37
+ # @api public
38
+ # @since 0.1.0
39
+ def configuration = Icons.config
40
+
41
+ alias_method :config, :configuration
42
+
43
+ # @return [Hash{Symbol => Icons::Library}] The registered icon libraries
44
+ #
45
+ # @api public
46
+ # @since 0.1.0
47
+ def libraries = Icons.libraries
48
+ end
49
+
50
+ if Hanami::CLI.within_hanami_app?
51
+ Hanami::CLI.register "generate icons", CLI::Commands::Generate::Icons
52
+ Hanami::CLI.register "generate icons:initializer", CLI::Commands::Generate::Initializer
53
+ Hanami::CLI.register "generate icons:sync", CLI::Commands::Generate::Sync
54
+ Hanami::CLI.register "generate icons:sprite", CLI::Commands::Generate::Sprite
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hanami_icons
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Rails Designer
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: hanami-view
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: hanami-cli
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: icons
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.11.0
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.11.0
68
+ description: Add any icon library to a Hanami app, from Heroicons, to Lucide to Tabler
69
+ (and others). Hanami Icons is library-agnostic, so you can add any library while
70
+ using the same interface.
71
+ email:
72
+ - devs@railsdesigner.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - Gemfile
78
+ - README.md
79
+ - Rakefile
80
+ - hanami_icons.gemspec
81
+ - lib/hanami_icons.rb
82
+ - lib/hanami_icons/cli/commands/generate/icons.rb
83
+ - lib/hanami_icons/cli/commands/generate/initializer.rb
84
+ - lib/hanami_icons/cli/commands/generate/sprite.rb
85
+ - lib/hanami_icons/cli/commands/generate/sync.rb
86
+ - lib/hanami_icons/cli/templates/provider.rb
87
+ - lib/hanami_icons/helpers/icon_helper.rb
88
+ - lib/hanami_icons/helpers/sprite_helper.rb
89
+ - lib/hanami_icons/version.rb
90
+ homepage: https://railsdesigner.com/open-source/hanami-icons/
91
+ licenses:
92
+ - MIT
93
+ metadata:
94
+ homepage_uri: https://railsdesigner.com/open-source/hanami-icons/
95
+ source_code_uri: https://github.com/Rails-Designer/hanami_icons
96
+ changelog_uri: https://github.com/Rails-Designer/hanami_icons/releases
97
+ bug_tracker_uri: https://github.com/Rails-Designer/hanami_icons/issues
98
+ documentation_uri: https://railsdesigner.com/open-source/hanami-icons/
99
+ rubygems_mfa_required: 'true'
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '3.3'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubygems_version: 4.0.22
115
+ specification_version: 4
116
+ summary: Add any icon library to a Hanami app
117
+ test_files: []