anyicon 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +110 -0
- data/Rakefile +14 -0
- data/app/helpers/anyicon/rails/icon_helper.rb +16 -0
- data/lib/anyicon/collections.rb +95 -0
- data/lib/anyicon/common.rb +36 -0
- data/lib/anyicon/configuration.rb +71 -0
- data/lib/anyicon/engine.rb +26 -0
- data/lib/anyicon/icon.rb +123 -0
- data/lib/anyicon/version.rb +5 -0
- data/lib/anyicon.rb +8 -0
- data/lib/generators/anyicon/install/install_generator.rb +30 -0
- data/lib/generators/anyicon/install/templates/anyicon.rb +33 -0
- data/lib/tasks/anyicon.rake +23 -0
- metadata +155 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6118b411159d81352c3d1ce3863139a440605e291705b4e14772051fa485bbea
|
4
|
+
data.tar.gz: 9038d868f28f9d2b8a6fb4bfb9367ae39cf32976f9a80d6df6393941d127771e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5848ddafbc9ef74ffc63946623a26e729ad422a8b435cbf76195c7d7c2990724bd6f76ffb95c8d74192c441d9698d1f01257b7317f76a2229402d5fa64692eec
|
7
|
+
data.tar.gz: 99c2beacea172b885659313fabf104410bc35b72dcd9efd226265cea549d914e44308d7d9f07dd5b5cd0b777931dbafbee7b3f06e1f2eb5bf83b68bce632a518
|
data/README.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# Anyicon
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/anyicon.svg)](https://badge.fury.io/rb/anyicon)
|
4
|
+
|
5
|
+
**Anyicon** provides Ruby on Rails view helpers for rendering icons from various collections hosted on GitHub.
|
6
|
+
|
7
|
+
<img src="docs/anyicon.png">
|
8
|
+
|
9
|
+
## How does it work
|
10
|
+
|
11
|
+
Anyicon simplifies the process of integrating and using SVG icons from various collections in your Rails application. Here's a breakdown of how it works:
|
12
|
+
|
13
|
+
1. **Configuration:** You can set up the icon collections you want to use in a Rails initializer (`config/initializers/anyicon.rb`) or you can use the already defined collections. Each collection is defined by specifying the GitHub repository, the path within the repository where the icons are located, and the branch to use.
|
14
|
+
|
15
|
+
2. **Icon Rendering:** When you call the `anyicon` helper in your views, it uses the `Anyicon::Icon` class to render the SVG content. The helper takes the icon name in the format `collection:icon_name` and optionally additional HTML properties.
|
16
|
+
|
17
|
+
3. **Fetching Icons:** If the requested icon is not already cached locally, the gem will fetch the SVG file from the specified GitHub repository. It uses the configuration settings to construct the URL, download the file, and store it in your application's `app/assets/images/icons` directory. **Attention to the license agreement of each collection**
|
18
|
+
|
19
|
+
4. **Caching:** Once downloaded, icons are cached locally to avoid repeated network requests. This ensures that your application remains performant and reduces dependency on external network availability.
|
20
|
+
|
21
|
+
5. **Helper Methods:** The `anyicon` helper method simplifies the process of including icons in your views by managing the rendering and fetching process transparently. You can also pass additional HTML attributes to customize the rendered SVG element.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Add this line to your application's Gemfile:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem 'anyicon'
|
29
|
+
```
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
```sh
|
34
|
+
bundle install
|
35
|
+
```
|
36
|
+
|
37
|
+
Or install it yourself as:
|
38
|
+
|
39
|
+
```sh
|
40
|
+
gem install anyicon
|
41
|
+
```
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
You can just use the anyicon helper in your views:
|
46
|
+
|
47
|
+
```erb
|
48
|
+
<%= anyicon icon: 'fontawesome_regular:address-book' %>
|
49
|
+
```
|
50
|
+
|
51
|
+
## Configuration
|
52
|
+
|
53
|
+
You can configure the icon collections in an initializer:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# config/initializers/anyicon.rb
|
57
|
+
Anyicon.configure do |config|
|
58
|
+
config.collections = {
|
59
|
+
my_custom_collection: { repo: 'user/repo', path: 'path/to/icons', branch: 'main' }
|
60
|
+
}
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
## Collections Available
|
65
|
+
|
66
|
+
| Collection | Github List | Example | Quantity | License |
|
67
|
+
|--------------------------------------|----------------------|----------------------------------|---------|---|
|
68
|
+
| [Font-Awesome](https://fontawesome.com/) | [fontawesome_regular](https://github.com/FortAwesome/Font-Awesome/tree/6.x/svgs/regular) | fontawesome_regular:address-book | 136 | [License](https://fontawesome.com/license) |
|
69
|
+
| | [fontawesome_solid](https://github.com/FortAwesome/Font-Awesome/tree/6.x/svgs/solid) | fontawesome_solid:award | 1,392 | |
|
70
|
+
| | [fontawesome_brands](https://github.com/FortAwesome/Font-Awesome/tree/6.x/svgs/brands) | fontawesome_brands:readme | 490 | |
|
71
|
+
| [Heroicons](https://heroicons.com/) | [heroicons_outline](https://github.com/tailwindlabs/heroicons/tree/master/optimized/24/outline) | heroicons_outline:check | 296 | [MIT](https://github.com/tailwindlabs/heroicons/blob/master/LICENSE) |
|
72
|
+
| | [heroicons_solid](https://github.com/tailwindlabs/heroicons/tree/master/optimized/24/solid) | heroicons_solid:cube | 296 | |
|
73
|
+
| [Tabler Icons](https://tabler-icons.io/) | [tabler_icons_filled](https://github.com/tabler/tabler-icons/tree/main/icons/filled) | tabler_icons_filled:alarm | 675 | [MIT](https://github.com/tabler/tabler-icons/blob/master/LICENSE) |
|
74
|
+
| | [tabler_icons_outline](https://github.com/tabler/tabler-icons/tree/main/icons/outline) | tabler_icons_outline:article | 4,615 | |
|
75
|
+
| [Mage Icons](https://mageicons.com/) | [mage_icons_fill](https://github.com/Mage-Icons/mage-icons/tree/main/svg/bulk) | mage_icons_fill:Book | 449 |[Apache 2.0](https://github.com/Mage-Icons/mage-icons/blob/main/License.txt) |
|
76
|
+
| | [mage_icons_stroke](https://github.com/Mage-Icons/mage-icons/tree/main/svg/stroke) | mage_icons_stroke:Archive | 545 | |
|
77
|
+
| | [mage_icons_social_bw](https://github.com/Mage-Icons/mage-icons/tree/main/svg/social-bw) | mage_icons_social_bw:Github | 50 | |
|
78
|
+
| | [mage_icons_social_color](https://github.com/Mage-Icons/mage-icons/tree/main/svg/social-color) | mage_icons_social_color:Youtube | 50 | |
|
79
|
+
| [Line Awesome](https://icons8.com/line-awesome) | [line_awesome](https://github.com/icons8/line-awesome/tree/master/svg) | line_awesome:film | 1,554 | MIT/[Good Boy License](https://icons8.com/good-boy-license/) |
|
80
|
+
| [@carbon/icons](https://github.com/carbon-design-system/carbon/tree/main/packages/icons) | [carbon](https://github.com/carbon-design-system/carbon/tree/main/packages/icons/src/svg/32) | carbon:arrow--left | 2,212 | [Apache 2.0](https://github.com/carbon-design-system/carbon/blob/main/LICENSE) |
|
81
|
+
| [IonIcons](https://ionic.io/ionicons) | [ionicons](https://github.com/ionic-team/ionicons/tree/main/src/svg) | ionicons:add-sharp | 1,356 | [MIT](https://github.com/ionic-team/ionicons/blob/main/LICENSE) |
|
82
|
+
| [Feather Icons](https://feathericons.com/) | [feather_icons](https://github.com/feathericons/feather/tree/main/icons) | feather_icons:airplay | 287 | [MIT](https://github.com/feathericons/feather/blob/master/LICENSE) |
|
83
|
+
|
84
|
+
Please, read the license before using any of these collections. This gem does not maintain or keep any of those files in it's repository. However, when you use any of the icons they will be automatically saved in `/app/assets/images/icons/` folder.
|
85
|
+
|
86
|
+
Fell free to add your own collection to this list.
|
87
|
+
|
88
|
+
## Development
|
89
|
+
|
90
|
+
To get started with development:
|
91
|
+
|
92
|
+
```
|
93
|
+
git clone https://github.com/arthurmolina/anyicon.git
|
94
|
+
cd heroicon
|
95
|
+
bundle install
|
96
|
+
bundle exec rake test
|
97
|
+
```
|
98
|
+
|
99
|
+
## Contributing
|
100
|
+
|
101
|
+
Anyone is encouraged to help improve this project. Here are a few ways you can help:
|
102
|
+
|
103
|
+
- [Report bugs](https://github.com/arthurmolina/anyicon/issues)
|
104
|
+
- Fix bugs and [submit pull requests](https://github.com/arthurmolina/anyicon/pulls)
|
105
|
+
- Write, clarify, or fix documentation
|
106
|
+
- Suggest or add new features
|
107
|
+
|
108
|
+
## License
|
109
|
+
|
110
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.libs << 'test'
|
10
|
+
t.pattern = 'test/**/*_test.rb'
|
11
|
+
t.verbose = false
|
12
|
+
end
|
13
|
+
|
14
|
+
task default: :test
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyicon
|
4
|
+
module Rails
|
5
|
+
module IconHelper
|
6
|
+
# Renders an icon using the Anyicon gem.
|
7
|
+
#
|
8
|
+
# @param icon [String] the name of the icon in the format 'collection:icon_name'
|
9
|
+
# @param props [Hash] additional properties to apply to the SVG element
|
10
|
+
# @return [String] the rendered SVG icon
|
11
|
+
def anyicon(icon:, **props)
|
12
|
+
Anyicon::Icon.render(icon:, **props)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module Anyicon
|
8
|
+
# The Collection class is responsible for managing icon collections
|
9
|
+
# from various repositories. It provides functionality to list and
|
10
|
+
# download all icons from a specified collection.
|
11
|
+
#
|
12
|
+
# Example usage:
|
13
|
+
#
|
14
|
+
# collection = Anyicon::Collection.new(:fontawesome_regular)
|
15
|
+
# collection.list # Lists all icons in the collection
|
16
|
+
# collection.download_all # Downloads all icons in the collection
|
17
|
+
#
|
18
|
+
# The class interacts with the configured collections in Anyicon::Configuration
|
19
|
+
# to determine the repository, path, and branch for each collection.
|
20
|
+
class Collection < Anyicon::Common
|
21
|
+
# Initializes a new Collection instance for the specified collection.
|
22
|
+
#
|
23
|
+
# @param collection [Symbol] the name of the icon collection
|
24
|
+
def initialize(collection)
|
25
|
+
super()
|
26
|
+
@collection = collection
|
27
|
+
end
|
28
|
+
|
29
|
+
# Lists all icons in the collection by fetching the directory contents from the repository.
|
30
|
+
#
|
31
|
+
# @return [Array<Hash>] a list of icons with their metadata
|
32
|
+
def list
|
33
|
+
response = fetch(collection_url)
|
34
|
+
JSON.parse(response.body)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Downloads all icons in the collection and saves them to the local file system.
|
38
|
+
#
|
39
|
+
# @return [void]
|
40
|
+
def download_all
|
41
|
+
count = 0
|
42
|
+
list.each do |icon|
|
43
|
+
count += 1
|
44
|
+
download(icon)
|
45
|
+
end
|
46
|
+
puts "#{@collection}: #{count} downloads."
|
47
|
+
end
|
48
|
+
|
49
|
+
# Retrieves the configured collections from Anyicon.
|
50
|
+
#
|
51
|
+
# @return [Hash] the configured collections
|
52
|
+
def collections
|
53
|
+
@collections ||= Anyicon::Configuration.new.collections
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Downloads a single icon and saves it to the local file system.
|
59
|
+
#
|
60
|
+
# @param icon [Hash] the metadata of the icon to download
|
61
|
+
# @return [void]
|
62
|
+
def download(icon)
|
63
|
+
return if icon['download_url'].nil?
|
64
|
+
return if File.exist?(icon_path(icon['name']))
|
65
|
+
|
66
|
+
FileUtils.mkdir_p(icon_path(icon['name']).dirname)
|
67
|
+
response = fetch(icon['download_url'])
|
68
|
+
File.write(icon_path(icon['name']), response.body)
|
69
|
+
rescue ActionView::Template::Error, ::OpenURI::HTTPError => e
|
70
|
+
::Rails.logger.error "AnyIcon: Failed to download icon: #{e.message}"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Constructs the local file path for the specified icon.
|
74
|
+
#
|
75
|
+
# @param icon_name [String] the name of the icon
|
76
|
+
# @return [Pathname] the path to the icon file
|
77
|
+
def icon_path(icon_name)
|
78
|
+
::Rails.root.join('app', 'assets', 'images', 'icons', @collection.to_s, icon_name)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Constructs the URL to fetch the icon collection directory contents from the repository.
|
82
|
+
#
|
83
|
+
# @return [String, nil] the URL to fetch the collection contents, or nil if the collection is not configured
|
84
|
+
def collection_url
|
85
|
+
return nil unless collections.keys.include?(@collection)
|
86
|
+
|
87
|
+
[
|
88
|
+
'https://api.github.com/repos/',
|
89
|
+
collections[@collection][:repo],
|
90
|
+
'/contents/',
|
91
|
+
collections[@collection][:path]
|
92
|
+
].join('')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyicon
|
4
|
+
# The Common class provides utility methods that can be used across the Anyicon gem.
|
5
|
+
# This class includes methods for making HTTP requests, handling redirects, and fetching
|
6
|
+
# content from specified URLs. It ensures that the HTTP requests follow redirects up to
|
7
|
+
# a specified limit to prevent infinite loops.
|
8
|
+
#
|
9
|
+
# Example usage:
|
10
|
+
#
|
11
|
+
# common = Anyicon::Common.new
|
12
|
+
# response = common.fetch('https://example.com')
|
13
|
+
# puts response.body if response.is_a?(Net::HTTPSuccess)
|
14
|
+
class Common
|
15
|
+
# Fetches the content from the given URL, following redirects if necessary.
|
16
|
+
#
|
17
|
+
# @param url [String] the URL to fetch
|
18
|
+
# @param limit [Integer] the maximum number of redirects to follow (default is 10)
|
19
|
+
# @return [Net::HTTPResponse] the HTTP response
|
20
|
+
# @raise [Net::HTTPError] if the number of redirects exceeds the limit or another HTTP error occurs
|
21
|
+
def fetch(url, limit = 10)
|
22
|
+
raise Net::HTTPError, 'Too many HTTP redirects' if limit.zero?
|
23
|
+
return nil if url.nil?
|
24
|
+
|
25
|
+
uri = URI.parse(URI::DEFAULT_PARSER.escape(url))
|
26
|
+
response = Net::HTTP.get_response(uri)
|
27
|
+
|
28
|
+
case response
|
29
|
+
when Net::HTTPSuccess then response
|
30
|
+
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
31
|
+
else
|
32
|
+
response.error!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The Configuration class is responsible for holding the configuration settings
|
4
|
+
# for the Anyicon gem. It provides a default set of icon collections that can be
|
5
|
+
# customized by the user.
|
6
|
+
module Anyicon
|
7
|
+
# Example usage:
|
8
|
+
#
|
9
|
+
# Anyicon.configure do |config|
|
10
|
+
# config.collections = {
|
11
|
+
# custom_collection: {
|
12
|
+
# repo: 'user/repo',
|
13
|
+
# path: 'path/to/icons',
|
14
|
+
# branch: 'main'
|
15
|
+
# }
|
16
|
+
# }
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# The class also allows setting additional configuration options such as
|
20
|
+
# `default_class`, which can be used to apply a default CSS class to every icon.
|
21
|
+
class Configuration
|
22
|
+
# A hash containing the default icon collections. Each collection specifies the
|
23
|
+
# repository, path, and branch where the icons can be found.
|
24
|
+
DEFAULT_COLLECTIONS = {
|
25
|
+
fontawesome_regular: { repo: 'FortAwesome/Font-Awesome', path: 'svgs/regular', branch: 'master' },
|
26
|
+
fontawesome_solid: { repo: 'FortAwesome/Font-Awesome', path: 'svgs/solid', branch: 'master' },
|
27
|
+
fontawesome_brands: { repo: 'FortAwesome/Font-Awesome', path: 'svgs/brands', branch: 'master' },
|
28
|
+
heroicons_outline: { repo: 'tailwindlabs/heroicons', path: 'optimized/24/outline', branch: 'master' },
|
29
|
+
heroicons_solid: { repo: 'tailwindlabs/heroicons', path: 'optimized/24/solid', branch: 'master' },
|
30
|
+
tabler_icons_filled: { repo: 'tabler/tabler-icons', path: 'icons/filled', branch: 'main' },
|
31
|
+
tabler_icons_outline: { repo: 'tabler/tabler-icons', path: 'icons/outline', branch: 'main' },
|
32
|
+
mage_icons_fill: { repo: 'Mage-Icons/mage-icons', path: 'svg/bulk', branch: 'main' },
|
33
|
+
mage_icons_stroke: { repo: 'Mage-Icons/mage-icons', path: 'svg/stroke', branch: 'main' },
|
34
|
+
mage_icons_social_bw: { repo: 'Mage-Icons/mage-icons', path: 'svg/social-bw', branch: 'main' },
|
35
|
+
mage_icons_social_color: { repo: 'Mage-Icons/mage-icons', path: 'svg/social-color', branch: 'main' },
|
36
|
+
line_awesome: { repo: 'icons8/line-awesome', path: 'svg', branch: 'master' },
|
37
|
+
carbon: { repo: 'carbon-design-system/carbon', path: 'packages/icons/src/svg/32', branch: 'main' },
|
38
|
+
ionicons: { repo: 'ionic-team/ionicons', path: 'src/svg', branch: 'main' },
|
39
|
+
feather_icons: { repo: 'feathericons/feather', path: 'icons', branch: 'main' }
|
40
|
+
}.freeze
|
41
|
+
|
42
|
+
# @return [Hash] the configured icon collections
|
43
|
+
attr_accessor :collections
|
44
|
+
|
45
|
+
# Initializes a new Configuration instance with default settings.
|
46
|
+
def initialize
|
47
|
+
@collections = DEFAULT_COLLECTIONS
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Provides access to the configuration instance.
|
52
|
+
#
|
53
|
+
# @return [Anyicon::Configuration] the configuration instance
|
54
|
+
def self.configuration
|
55
|
+
@configuration ||= Configuration.new
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sets the configuration instance.
|
59
|
+
#
|
60
|
+
# @param config [Anyicon::Configuration] the configuration instance to set
|
61
|
+
def self.configuration=(config)
|
62
|
+
@configuration = config
|
63
|
+
end
|
64
|
+
|
65
|
+
# Yields the configuration instance to a block for customization.
|
66
|
+
#
|
67
|
+
# @yieldparam [Anyicon::Configuration] config the configuration instance
|
68
|
+
def self.configure
|
69
|
+
yield configuration
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyicon
|
4
|
+
# The Engine class is responsible for integrating the Anyicon gem with a Ruby on Rails application.
|
5
|
+
# It inherits from Rails::Engine, which allows it to hook into the Rails framework and provide
|
6
|
+
# the necessary configurations and initializations for the gem.
|
7
|
+
#
|
8
|
+
# The engine ensures that icons are precompiled as part of the Rails asset pipeline, making them
|
9
|
+
# available for use in the application's views.
|
10
|
+
#
|
11
|
+
# Example usage in a Rails application:
|
12
|
+
#
|
13
|
+
# # In a Rails initializer (config/initializers/anyicon.rb)
|
14
|
+
# Anyicon.configure do |config|
|
15
|
+
# config.collections = {
|
16
|
+
# custom_collection: { repo: 'user/repo', path: 'path/to/icons', branch: 'main' }
|
17
|
+
# }
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# This configuration allows the application to specify additional icon collections that can be
|
21
|
+
# used with the Anyicon helper methods.
|
22
|
+
module Rails
|
23
|
+
class Engine < ::Rails::Engine
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/anyicon/icon.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module Anyicon
|
8
|
+
# The Icon class is responsible for managing the rendering of icons from various
|
9
|
+
# collections available on GitHub. It handles downloading and caching of icons
|
10
|
+
# to ensure they are available for use in a Ruby on Rails application.
|
11
|
+
#
|
12
|
+
# Example usage:
|
13
|
+
#
|
14
|
+
# icon = Anyicon::Icon.new(icon: 'fontawesome_regular:address-book')
|
15
|
+
# icon.render
|
16
|
+
#
|
17
|
+
# The class supports additional properties that can be passed in to customize
|
18
|
+
# the SVG elements.
|
19
|
+
class Icon < Anyicon::Common
|
20
|
+
# Initializes a new Icon instance.
|
21
|
+
#
|
22
|
+
# @param icon [String] a comma-separated string of icon names, each in the format 'collection:name'
|
23
|
+
# @param props [Hash] additional properties to apply to the SVG element
|
24
|
+
def initialize(icon:, **props)
|
25
|
+
super()
|
26
|
+
@icons = icon.split(',').map { |i| i.split(':') }
|
27
|
+
@props = props
|
28
|
+
end
|
29
|
+
|
30
|
+
# Renders the SVG content for the specified icons.
|
31
|
+
#
|
32
|
+
# @return [String] the HTML-safe SVG content
|
33
|
+
def render
|
34
|
+
result = ''.html_safe
|
35
|
+
@icons.each do |icon|
|
36
|
+
ensure_icon_exists(icon)
|
37
|
+
result.concat(svg_content(icon).html_safe)
|
38
|
+
end
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Retrieves the collections configuration.
|
45
|
+
#
|
46
|
+
# @return [Hash] the collections configuration
|
47
|
+
def collections
|
48
|
+
@collections ||= Anyicon.configuration.collections
|
49
|
+
end
|
50
|
+
|
51
|
+
# Ensures the specified icon exists by downloading it if necessary.
|
52
|
+
#
|
53
|
+
# @param icon [Array] the collection and name of the icon
|
54
|
+
def ensure_icon_exists(icon)
|
55
|
+
return if File.exist?(icon_path(icon))
|
56
|
+
|
57
|
+
download_icon(icon)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Downloads the specified icon from the configured collection.
|
61
|
+
#
|
62
|
+
# @param icon [Array] the collection and name of the icon
|
63
|
+
def download_icon(icon)
|
64
|
+
url = icon_url(icon)
|
65
|
+
return unless url
|
66
|
+
|
67
|
+
FileUtils.mkdir_p(icon_path(icon).dirname)
|
68
|
+
response = fetch(url)
|
69
|
+
File.write(icon_path(icon), response.body) if response.is_a?(Net::HTTPSuccess)
|
70
|
+
rescue ActionView::Template::Error, Net::HTTPError => e
|
71
|
+
::Rails.logger.error "AnyIcon: Failed to download icon: #{e.message}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the local file path for the specified icon.
|
75
|
+
#
|
76
|
+
# @param icon [Array] the collection and name of the icon
|
77
|
+
# @return [Pathname] the path to the icon file
|
78
|
+
def icon_path(icon)
|
79
|
+
::Rails.root.join('app', 'assets', 'images', 'icons', icon[0], "#{icon[1]}.svg")
|
80
|
+
end
|
81
|
+
|
82
|
+
# Constructs the URL to download the specified icon.
|
83
|
+
#
|
84
|
+
# @param icon [Array] the collection and name of the icon
|
85
|
+
# @return [String, nil] the URL to download the icon, or nil if the collection is not configured
|
86
|
+
def icon_url(icon)
|
87
|
+
return nil unless collections.keys.include?(icon[0].to_sym)
|
88
|
+
|
89
|
+
['https://github.com/', collections[icon[0].to_sym][:repo], '/raw/', collections[icon[0].to_sym][:branch], '/',
|
90
|
+
collections[icon[0].to_sym][:path], '/', icon[1], '.svg'].join('')
|
91
|
+
end
|
92
|
+
|
93
|
+
# Reads and customizes the SVG content for the specified icon.
|
94
|
+
#
|
95
|
+
# @param icon [Array] the collection and name of the icon
|
96
|
+
# @return [String] the customized SVG content
|
97
|
+
def svg_content(icon)
|
98
|
+
return '' unless File.file?(icon_path(icon))
|
99
|
+
|
100
|
+
svg_content = File.read(icon_path(icon))
|
101
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(svg_content)
|
102
|
+
svg = doc.at_css 'svg'
|
103
|
+
|
104
|
+
@props.each do |key, value|
|
105
|
+
value = "#{value} #{icon[-2..].join(' ')}" if key == :class && icon.count > 2
|
106
|
+
|
107
|
+
svg[key.to_s] = value
|
108
|
+
end
|
109
|
+
|
110
|
+
doc.to_html
|
111
|
+
end
|
112
|
+
|
113
|
+
class << self
|
114
|
+
# Renders the SVG content for the specified icons.
|
115
|
+
#
|
116
|
+
# @param kwargs [Hash] the parameters for initializing an Icon instance
|
117
|
+
# @return [String] the HTML-safe SVG content
|
118
|
+
def render(**kwargs)
|
119
|
+
new(**kwargs).render
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/anyicon.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'rails/generators'
|
3
|
+
|
4
|
+
module Anyicon
|
5
|
+
module Generators
|
6
|
+
# The InstallGenerator class is a Rails generator that sets up the initial configuration
|
7
|
+
# for the Anyicon gem. This generator copies a template configuration file into the
|
8
|
+
# Rails application's initializers directory, allowing the user to customize the icon
|
9
|
+
# collections and other settings.
|
10
|
+
#
|
11
|
+
# Example usage:
|
12
|
+
#
|
13
|
+
# # Run the generator from the command line
|
14
|
+
# rails generate anyicon:install
|
15
|
+
#
|
16
|
+
# This will copy the `anyicon.rb` template to `config/initializers/anyicon.rb` in your
|
17
|
+
# Rails application.
|
18
|
+
class InstallGenerator < ::Rails::Generators::Base
|
19
|
+
source_root File.join(__dir__, 'templates')
|
20
|
+
desc "This generator installs AnyIcon"
|
21
|
+
|
22
|
+
# Copies the anyicon configuration template to the initializers directory.
|
23
|
+
#
|
24
|
+
# @return [void]
|
25
|
+
def copy_config
|
26
|
+
template 'anyicon.rb', 'config/initializers/anyicon.rb'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Anyicon.configure do |config|
|
4
|
+
##
|
5
|
+
# You can set the icon collections here.
|
6
|
+
# Each collection should have a repository, path, and branch specified.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# config.collections = {
|
11
|
+
# custom_collection: {
|
12
|
+
# repo: 'user/repo',
|
13
|
+
# path: 'path/to/icons',
|
14
|
+
# branch: 'main'
|
15
|
+
# }
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
|
19
|
+
config.collections = {
|
20
|
+
# Add your icon collections here
|
21
|
+
# Example:
|
22
|
+
# fontawesome_regular: {
|
23
|
+
# repo: 'FortAwesome/Font-Awesome',
|
24
|
+
# path: 'svgs/regular',
|
25
|
+
# branch: 'master'
|
26
|
+
# },
|
27
|
+
# heroicons_solid: {
|
28
|
+
# repo: 'tailwindlabs/heroicons',
|
29
|
+
# path: 'optimized/24/solid',
|
30
|
+
# branch: 'master'
|
31
|
+
# }
|
32
|
+
}
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :anyicon do
|
4
|
+
desc 'Download a specific icon collection'
|
5
|
+
task :download_collection, [:collection] => :environment do |_t, args|
|
6
|
+
collection = args[:collection]
|
7
|
+
#binding.pry
|
8
|
+
if Anyicon::Configuration.new.collections.keys.include?(collection.to_sym)
|
9
|
+
Anyicon::Collection.new(collection.to_sym).download_all
|
10
|
+
else
|
11
|
+
puts "Collection #{collection} not found."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Download all icon collections'
|
16
|
+
task download_all_collections: :environment do
|
17
|
+
puts 'Downloading all icon collections'
|
18
|
+
Anyicon::Configuration.new.collections.each_key do |collection|
|
19
|
+
puts "Downloading #{collection}..."
|
20
|
+
Anyicon::Collection.new(collection).download_all
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: anyicon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Arthur Molina
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-28 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: '5.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: appraisal
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mocha
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sqlite3
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: standard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Ruby on Rails View Helpers for any icon collections that have github
|
112
|
+
repository available.
|
113
|
+
email:
|
114
|
+
- arthurmolina@gmail.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- README.md
|
120
|
+
- Rakefile
|
121
|
+
- app/helpers/anyicon/rails/icon_helper.rb
|
122
|
+
- lib/anyicon.rb
|
123
|
+
- lib/anyicon/collections.rb
|
124
|
+
- lib/anyicon/common.rb
|
125
|
+
- lib/anyicon/configuration.rb
|
126
|
+
- lib/anyicon/engine.rb
|
127
|
+
- lib/anyicon/icon.rb
|
128
|
+
- lib/anyicon/version.rb
|
129
|
+
- lib/generators/anyicon/install/install_generator.rb
|
130
|
+
- lib/generators/anyicon/install/templates/anyicon.rb
|
131
|
+
- lib/tasks/anyicon.rake
|
132
|
+
homepage: https://github.com/arthurmolina/anyicon
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '2.7'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubygems_version: 3.5.6
|
152
|
+
signing_key:
|
153
|
+
specification_version: 4
|
154
|
+
summary: Rails View Helpers for any icon collections.
|
155
|
+
test_files: []
|