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 +7 -0
- data/Gemfile +9 -0
- data/README.md +228 -0
- data/Rakefile +17 -0
- data/hanami_icons.gemspec +33 -0
- data/lib/hanami_icons/cli/commands/generate/icons.rb +71 -0
- data/lib/hanami_icons/cli/commands/generate/initializer.rb +171 -0
- data/lib/hanami_icons/cli/commands/generate/sprite.rb +35 -0
- data/lib/hanami_icons/cli/commands/generate/sync.rb +43 -0
- data/lib/hanami_icons/cli/templates/provider.rb +12 -0
- data/lib/hanami_icons/helpers/icon_helper.rb +64 -0
- data/lib/hanami_icons/helpers/sprite_helper.rb +58 -0
- data/lib/hanami_icons/version.rb +3 -0
- data/lib/hanami_icons.rb +56 -0
- metadata +117 -0
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
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,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
|
data/lib/hanami_icons.rb
ADDED
|
@@ -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: []
|