anyicon 1.0.3 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +49 -2
- data/app/helpers/anyicon/rails/icon_helper.rb +2 -2
- data/lib/anyicon/collections.rb +22 -17
- data/lib/anyicon/common.rb +16 -4
- data/lib/anyicon/configuration.rb +19 -15
- data/lib/anyicon/icon.rb +69 -20
- data/lib/anyicon/version.rb +1 -1
- data/lib/anyicon.rb +6 -6
- data/lib/generators/anyicon/install/install_generator.rb +4 -4
- data/lib/generators/anyicon/install/templates/anyicon.rb +7 -0
- data/lib/tasks/anyicon.rake +4 -4
- metadata +17 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf910787f8f2afc33957a422c85c68bb6453522921dd9d1bbe8af16abea8370a
|
|
4
|
+
data.tar.gz: 4b3a381baec2cfd44707c1ac7bb37d2ccb5b23fa607d05695c4e827582559320
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60e1cb0856388ebf05ddd3cb4bd037445fc0e8191355079a8ee62b79f09f42e55b3be238484248af4a1578551b3fdc1e84e01a46c37e8481b84d325c9883ef72
|
|
7
|
+
data.tar.gz: '07293138a74f9cea182743a7700cd9cb8f3af4bd3e6dfd8fc2781b522ef1cc42c2f4d8fcb8a2cdd42cd583af9d48f81806271060b8f20b09b1441c97d0bb423e'
|
data/README.md
CHANGED
|
@@ -47,6 +47,11 @@ You can just use the anyicon helper in your views:
|
|
|
47
47
|
```erb
|
|
48
48
|
<%= anyicon icon: 'fontawesome_regular:address-book' %>
|
|
49
49
|
```
|
|
50
|
+
or
|
|
51
|
+
|
|
52
|
+
```erb
|
|
53
|
+
<%= anyicon 'fontawesome_regular:address-book' %>
|
|
54
|
+
```
|
|
50
55
|
|
|
51
56
|
## Configuration
|
|
52
57
|
|
|
@@ -61,6 +66,33 @@ Anyicon.configure do |config|
|
|
|
61
66
|
end
|
|
62
67
|
```
|
|
63
68
|
|
|
69
|
+
Or add new collections while keeping the defaults:
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
Anyicon.configure do |config|
|
|
73
|
+
config.add_collections(
|
|
74
|
+
my_custom_collection: { repo: 'user/repo', path: 'path/to/icons', branch: 'main' }
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### GitHub Token
|
|
80
|
+
|
|
81
|
+
Anyicon fetches icons from GitHub. Without authentication, the GitHub API limits requests to **60 per hour**. If you use `Anyicon::Collection` to download entire collections, or your app fetches many icons on first deploy, you may hit this limit.
|
|
82
|
+
|
|
83
|
+
Setting a GitHub personal access token raises the limit to **5,000 requests per hour**. The token is also used when downloading individual icons.
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
# config/initializers/anyicon.rb
|
|
87
|
+
Anyicon.configure do |config|
|
|
88
|
+
config.github_token = ENV["GITHUB_TOKEN"]
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
To create a token, go to [GitHub Settings > Developer settings > Personal access tokens > Fine-grained tokens](https://github.com/settings/tokens?type=beta) and generate a token. No special permissions/scopes are needed — public repository read access is sufficient.
|
|
93
|
+
|
|
94
|
+
> **Note:** This is optional. If you only use a few icons and they are already cached locally in `app/assets/images/icons/`, no API calls are made and no token is needed.
|
|
95
|
+
|
|
64
96
|
## Collections Available
|
|
65
97
|
|
|
66
98
|
| Collection | Github List | Example | Quantity | License |
|
|
@@ -85,13 +117,28 @@ Please, read the license before using any of these collections. This gem does no
|
|
|
85
117
|
|
|
86
118
|
Fell free to add your own collection to this list.
|
|
87
119
|
|
|
120
|
+
## Demo
|
|
121
|
+
|
|
122
|
+
To see Anyicon in action with an interactive demo page:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
git clone https://github.com/arthurmolina/anyicon.git
|
|
126
|
+
cd anyicon
|
|
127
|
+
bundle install
|
|
128
|
+
RAILS_ENV=development bundle exec rackup -p 3000 test/dummy/config.ru
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Then open [http://localhost:3000/demo](http://localhost:3000/demo).
|
|
132
|
+
|
|
133
|
+
The demo showcases basic usage, sizing, colors, HTML/data/aria attributes, inline text components, and CSS animations.
|
|
134
|
+
|
|
88
135
|
## Development
|
|
89
136
|
|
|
90
137
|
To get started with development:
|
|
91
138
|
|
|
92
|
-
```
|
|
139
|
+
```sh
|
|
93
140
|
git clone https://github.com/arthurmolina/anyicon.git
|
|
94
|
-
cd
|
|
141
|
+
cd anyicon
|
|
95
142
|
bundle install
|
|
96
143
|
bundle exec rake test
|
|
97
144
|
```
|
|
@@ -8,8 +8,8 @@ module Anyicon
|
|
|
8
8
|
# @param icon [String] the name of the icon in the format 'collection:icon_name'
|
|
9
9
|
# @param props [Hash] additional properties to apply to the SVG element
|
|
10
10
|
# @return [String] the rendered SVG icon
|
|
11
|
-
def anyicon(icon
|
|
12
|
-
Anyicon::Icon.render(icon
|
|
11
|
+
def anyicon(icon = nil, **props)
|
|
12
|
+
Anyicon::Icon.render(icon, **props)
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
end
|
data/lib/anyicon/collections.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "fileutils"
|
|
6
6
|
|
|
7
7
|
module Anyicon
|
|
8
8
|
# The Collection class is responsible for managing icon collections
|
|
@@ -31,7 +31,8 @@ module Anyicon
|
|
|
31
31
|
# @return [Array<Hash>] a list of icons with their metadata
|
|
32
32
|
def list
|
|
33
33
|
response = fetch(collection_url)
|
|
34
|
-
JSON.parse(response&.body ||
|
|
34
|
+
result = JSON.parse(response&.body || "[]")
|
|
35
|
+
result.is_a?(Array) ? result : []
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
# Downloads all icons in the collection and saves them to the local file system.
|
|
@@ -39,7 +40,7 @@ module Anyicon
|
|
|
39
40
|
# @return [void]
|
|
40
41
|
def download_all
|
|
41
42
|
if list.empty?
|
|
42
|
-
|
|
43
|
+
::Rails.logger.info "AnyIcon: No icons available for #{@collection}."
|
|
43
44
|
return
|
|
44
45
|
end
|
|
45
46
|
|
|
@@ -48,7 +49,7 @@ module Anyicon
|
|
|
48
49
|
count += 1
|
|
49
50
|
download(icon)
|
|
50
51
|
end
|
|
51
|
-
|
|
52
|
+
::Rails.logger.info "AnyIcon: #{@collection}: #{count} downloads."
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
# Retrieves the configured collections from Anyicon.
|
|
@@ -65,12 +66,12 @@ module Anyicon
|
|
|
65
66
|
# @param icon [Hash] the metadata of the icon to download
|
|
66
67
|
# @return [void]
|
|
67
68
|
def download(icon)
|
|
68
|
-
return if icon[
|
|
69
|
-
return if File.exist?(icon_path(icon[
|
|
69
|
+
return if icon["download_url"].nil?
|
|
70
|
+
return if File.exist?(icon_path(icon["name"]))
|
|
70
71
|
|
|
71
|
-
FileUtils.mkdir_p(icon_path(icon[
|
|
72
|
-
response = fetch(icon[
|
|
73
|
-
File.write(icon_path(icon[
|
|
72
|
+
FileUtils.mkdir_p(icon_path(icon["name"]).dirname)
|
|
73
|
+
response = fetch(icon["download_url"])
|
|
74
|
+
File.write(icon_path(icon["name"]), response.body)
|
|
74
75
|
rescue ActionView::Template::Error, Net::HTTPError, Net::HTTPClientException => e
|
|
75
76
|
::Rails.logger.error "AnyIcon: Failed to download icon: #{e.message}"
|
|
76
77
|
end
|
|
@@ -80,21 +81,25 @@ module Anyicon
|
|
|
80
81
|
# @param icon_name [String] the name of the icon
|
|
81
82
|
# @return [Pathname] the path to the icon file
|
|
82
83
|
def icon_path(icon_name)
|
|
83
|
-
|
|
84
|
+
sanitized_collection = File.basename(@collection.to_s.gsub(/[^a-zA-Z0-9_\-]/, ""))
|
|
85
|
+
sanitized_name = File.basename(icon_name.to_s)
|
|
86
|
+
::Rails.root.join("app", "assets", "images", "icons", sanitized_collection, sanitized_name)
|
|
84
87
|
end
|
|
85
88
|
|
|
86
89
|
# Constructs the URL to fetch the icon collection directory contents from the repository.
|
|
87
90
|
#
|
|
88
91
|
# @return [String, nil] the URL to fetch the collection contents, or nil if the collection is not configured
|
|
89
92
|
def collection_url
|
|
90
|
-
return nil unless collections.
|
|
93
|
+
return nil unless collections.key?(@collection)
|
|
91
94
|
|
|
92
95
|
[
|
|
93
|
-
|
|
96
|
+
"https://api.github.com/repos/",
|
|
94
97
|
collections[@collection][:repo],
|
|
95
|
-
|
|
96
|
-
collections[@collection][:path]
|
|
97
|
-
|
|
98
|
+
"/contents/",
|
|
99
|
+
collections[@collection][:path],
|
|
100
|
+
"?ref=",
|
|
101
|
+
collections[@collection][:branch]
|
|
102
|
+
].join("")
|
|
98
103
|
end
|
|
99
104
|
end
|
|
100
105
|
end
|
data/lib/anyicon/common.rb
CHANGED
|
@@ -12,6 +12,8 @@ module Anyicon
|
|
|
12
12
|
# response = common.fetch('https://example.com')
|
|
13
13
|
# puts response.body if response.is_a?(Net::HTTPSuccess)
|
|
14
14
|
class Common
|
|
15
|
+
ALLOWED_HOSTS = %w[github.com raw.githubusercontent.com objects.githubusercontent.com api.github.com].freeze
|
|
16
|
+
|
|
15
17
|
# Fetches the content from the given URL, following redirects if necessary.
|
|
16
18
|
#
|
|
17
19
|
# @param url [String] the URL to fetch
|
|
@@ -19,15 +21,25 @@ module Anyicon
|
|
|
19
21
|
# @return [Net::HTTPResponse] the HTTP response
|
|
20
22
|
# @raise [Net::HTTPError] if the number of redirects exceeds the limit or another HTTP error occurs
|
|
21
23
|
def fetch(url, limit = 10)
|
|
22
|
-
raise Net::HTTPError
|
|
24
|
+
raise Net::HTTPError.new("Too many HTTP redirects", nil) if limit.zero?
|
|
23
25
|
return nil if url.nil?
|
|
24
26
|
|
|
25
|
-
uri = URI.parse(URI::
|
|
26
|
-
|
|
27
|
+
uri = URI.parse(URI::RFC2396_PARSER.escape(url))
|
|
28
|
+
unless uri.is_a?(URI::HTTPS) && ALLOWED_HOSTS.include?(uri.host)
|
|
29
|
+
raise Net::HTTPError.new("Blocked request to disallowed host: #{uri.host}", nil)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
request = Net::HTTP::Get.new(uri)
|
|
33
|
+
token = Anyicon.configuration.github_token
|
|
34
|
+
request["Authorization"] = "token #{token}" if token
|
|
35
|
+
|
|
36
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
|
37
|
+
http.request(request)
|
|
38
|
+
end
|
|
27
39
|
|
|
28
40
|
case response
|
|
29
41
|
when Net::HTTPSuccess then response
|
|
30
|
-
when Net::HTTPRedirection then fetch(response[
|
|
42
|
+
when Net::HTTPRedirection then fetch(response["location"], limit - 1)
|
|
31
43
|
else
|
|
32
44
|
response.error!
|
|
33
45
|
end
|
|
@@ -22,29 +22,33 @@ module Anyicon
|
|
|
22
22
|
# A hash containing the default icon collections. Each collection specifies the
|
|
23
23
|
# repository, path, and branch where the icons can be found.
|
|
24
24
|
DEFAULT_COLLECTIONS = {
|
|
25
|
-
fontawesome_regular: { repo:
|
|
26
|
-
fontawesome_solid: { repo:
|
|
27
|
-
fontawesome_brands: { repo:
|
|
28
|
-
heroicons_outline: { repo:
|
|
29
|
-
heroicons_solid: { repo:
|
|
30
|
-
tabler_icons_filled: { repo:
|
|
31
|
-
tabler_icons_outline: { repo:
|
|
32
|
-
mage_icons_fill: { repo:
|
|
33
|
-
mage_icons_stroke: { repo:
|
|
34
|
-
mage_icons_social_bw: { repo:
|
|
35
|
-
mage_icons_social_color: { repo:
|
|
36
|
-
line_awesome: { repo:
|
|
37
|
-
carbon: { repo:
|
|
38
|
-
ionicons: { repo:
|
|
39
|
-
feather_icons: { repo:
|
|
25
|
+
fontawesome_regular: { repo: "FortAwesome/Font-Awesome", path: "svgs/regular", branch: "6.x" },
|
|
26
|
+
fontawesome_solid: { repo: "FortAwesome/Font-Awesome", path: "svgs/solid", branch: "6.x" },
|
|
27
|
+
fontawesome_brands: { repo: "FortAwesome/Font-Awesome", path: "svgs/brands", branch: "6.x" },
|
|
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
40
|
}.freeze
|
|
41
41
|
|
|
42
42
|
# @return [Hash] the configured icon collections
|
|
43
43
|
attr_accessor :collections
|
|
44
44
|
|
|
45
|
+
# @return [String, nil] optional GitHub personal access token for API requests
|
|
46
|
+
attr_accessor :github_token
|
|
47
|
+
|
|
45
48
|
# Initializes a new Configuration instance with default settings.
|
|
46
49
|
def initialize
|
|
47
50
|
@collections = DEFAULT_COLLECTIONS.dup
|
|
51
|
+
@github_token = nil
|
|
48
52
|
end
|
|
49
53
|
|
|
50
54
|
def add_collections(new_collections)
|
data/lib/anyicon/icon.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "nokogiri"
|
|
5
|
+
require "fileutils"
|
|
6
6
|
|
|
7
7
|
module Anyicon
|
|
8
8
|
# The Icon class is responsible for managing the rendering of icons from various
|
|
@@ -21,22 +21,29 @@ module Anyicon
|
|
|
21
21
|
#
|
|
22
22
|
# @param icon [String] a comma-separated string of icon names, each in the format 'collection:name'
|
|
23
23
|
# @param props [Hash] additional properties to apply to the SVG element
|
|
24
|
-
|
|
24
|
+
ALLOWED_ATTRIBUTES = %w[
|
|
25
|
+
class id style width height viewBox fill stroke
|
|
26
|
+
stroke-width opacity transform title aria-label aria-hidden role
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
DATA_ATTRIBUTE_PATTERN = /\Adata-[\w-]+\z/
|
|
30
|
+
|
|
31
|
+
def initialize(icon = nil, **props)
|
|
25
32
|
super()
|
|
26
|
-
@icons = icon.to_s.split(
|
|
27
|
-
@
|
|
33
|
+
@icons = (icon || props[:icon]).to_s.split(",").map { |i| i.split(":") }
|
|
34
|
+
@icons.reject! { |i| i.length < 2 }
|
|
35
|
+
@props = props.select { |key, _| allowed_attribute?(key) }
|
|
28
36
|
end
|
|
29
37
|
|
|
30
38
|
# Renders the SVG content for the specified icons.
|
|
31
39
|
#
|
|
32
40
|
# @return [String] the HTML-safe SVG content
|
|
33
41
|
def render
|
|
34
|
-
|
|
35
|
-
@icons.each do |icon|
|
|
42
|
+
parts = @icons.map do |icon|
|
|
36
43
|
ensure_icon_exists(icon)
|
|
37
|
-
|
|
44
|
+
svg_content(icon)
|
|
38
45
|
end
|
|
39
|
-
|
|
46
|
+
ActiveSupport::SafeBuffer.new(parts.join)
|
|
40
47
|
end
|
|
41
48
|
|
|
42
49
|
private
|
|
@@ -48,6 +55,23 @@ module Anyicon
|
|
|
48
55
|
@collections ||= Anyicon.configuration.collections
|
|
49
56
|
end
|
|
50
57
|
|
|
58
|
+
# Checks if an attribute key is allowed on the SVG element.
|
|
59
|
+
#
|
|
60
|
+
# @param key [Symbol, String] the attribute key
|
|
61
|
+
# @return [Boolean]
|
|
62
|
+
def allowed_attribute?(key)
|
|
63
|
+
name = key.to_s
|
|
64
|
+
ALLOWED_ATTRIBUTES.include?(name) || name.match?(DATA_ATTRIBUTE_PATTERN)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Sanitizes an icon name component to prevent path traversal.
|
|
68
|
+
#
|
|
69
|
+
# @param name [String] the raw icon name component
|
|
70
|
+
# @return [String] the sanitized name
|
|
71
|
+
def sanitize_name(name)
|
|
72
|
+
File.basename(name.to_s.gsub(/[^a-zA-Z0-9_\-]/, ""))
|
|
73
|
+
end
|
|
74
|
+
|
|
51
75
|
# Ensures the specified icon exists by downloading it if necessary.
|
|
52
76
|
#
|
|
53
77
|
# @param icon [Array] the collection and name of the icon
|
|
@@ -76,7 +100,7 @@ module Anyicon
|
|
|
76
100
|
# @param icon [Array] the collection and name of the icon
|
|
77
101
|
# @return [Pathname] the path to the icon file
|
|
78
102
|
def icon_path(icon)
|
|
79
|
-
::Rails.root.join(
|
|
103
|
+
::Rails.root.join("app", "assets", "images", "icons", sanitize_name(icon[0]), "#{sanitize_name(icon[1])}.svg")
|
|
80
104
|
end
|
|
81
105
|
|
|
82
106
|
# Constructs the URL to download the specified icon.
|
|
@@ -84,10 +108,22 @@ module Anyicon
|
|
|
84
108
|
# @param icon [Array] the collection and name of the icon
|
|
85
109
|
# @return [String, nil] the URL to download the icon, or nil if the collection is not configured
|
|
86
110
|
def icon_url(icon)
|
|
87
|
-
|
|
111
|
+
collection_key = sanitize_name(icon[0]).to_sym
|
|
112
|
+
return nil unless collections.key?(collection_key)
|
|
113
|
+
|
|
114
|
+
[ "https://github.com/", collections[collection_key][:repo], "/raw/", collections[collection_key][:branch], "/",
|
|
115
|
+
collections[collection_key][:path], "/", sanitize_name(icon[1]), ".svg" ].join("")
|
|
116
|
+
end
|
|
88
117
|
|
|
89
|
-
|
|
90
|
-
|
|
118
|
+
# Returns the cached raw SVG content for the specified icon.
|
|
119
|
+
#
|
|
120
|
+
# @param icon [Array] the collection and name of the icon
|
|
121
|
+
# @return [String, nil] the raw SVG file content, or nil if file doesn't exist
|
|
122
|
+
def cached_svg(icon)
|
|
123
|
+
path = icon_path(icon)
|
|
124
|
+
return nil unless File.file?(path)
|
|
125
|
+
|
|
126
|
+
self.class.svg_cache[path.to_s] ||= File.read(path)
|
|
91
127
|
end
|
|
92
128
|
|
|
93
129
|
# Reads and customizes the SVG content for the specified icon.
|
|
@@ -95,11 +131,11 @@ module Anyicon
|
|
|
95
131
|
# @param icon [Array] the collection and name of the icon
|
|
96
132
|
# @return [String] the customized SVG content
|
|
97
133
|
def svg_content(icon)
|
|
98
|
-
|
|
134
|
+
raw = cached_svg(icon)
|
|
135
|
+
return "" unless raw
|
|
99
136
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
svg = doc.at_css 'svg'
|
|
137
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(raw)
|
|
138
|
+
svg = doc.at_css "svg"
|
|
103
139
|
|
|
104
140
|
@props.each do |key, value|
|
|
105
141
|
value = "#{value} #{icon[-2..].join(' ')}" if key == :class && icon.count > 2
|
|
@@ -115,8 +151,21 @@ module Anyicon
|
|
|
115
151
|
#
|
|
116
152
|
# @param kwargs [Hash] the parameters for initializing an Icon instance
|
|
117
153
|
# @return [String] the HTML-safe SVG content
|
|
118
|
-
def render(**kwargs)
|
|
119
|
-
new(**kwargs).render
|
|
154
|
+
def render(*args, **kwargs)
|
|
155
|
+
new(*args, **kwargs).render
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# In-memory cache for raw SVG file contents, keyed by file path.
|
|
159
|
+
# Avoids repeated File.read + disk I/O for the same icon.
|
|
160
|
+
#
|
|
161
|
+
# @return [Hash] the SVG cache
|
|
162
|
+
def svg_cache
|
|
163
|
+
@svg_cache ||= {}
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Clears the in-memory SVG cache.
|
|
167
|
+
def clear_cache!
|
|
168
|
+
@svg_cache = {}
|
|
120
169
|
end
|
|
121
170
|
end
|
|
122
171
|
end
|
data/lib/anyicon/version.rb
CHANGED
data/lib/anyicon.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
3
|
+
require "rails"
|
|
4
|
+
require "anyicon/engine"
|
|
5
|
+
require "anyicon/common"
|
|
6
|
+
require "anyicon/collections"
|
|
7
|
+
require "anyicon/icon"
|
|
8
|
+
require "anyicon/configuration"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "rails/generators"
|
|
4
4
|
|
|
5
5
|
module Anyicon
|
|
6
6
|
module Generators
|
|
@@ -17,14 +17,14 @@ module Anyicon
|
|
|
17
17
|
# This will copy the `anyicon.rb` template to `config/initializers/anyicon.rb` in your
|
|
18
18
|
# Rails application.
|
|
19
19
|
class InstallGenerator < ::Rails::Generators::Base
|
|
20
|
-
source_root File.join(__dir__,
|
|
21
|
-
desc
|
|
20
|
+
source_root File.join(__dir__, "templates")
|
|
21
|
+
desc "This generator installs AnyIcon"
|
|
22
22
|
|
|
23
23
|
# Copies the anyicon configuration template to the initializers directory.
|
|
24
24
|
#
|
|
25
25
|
# @return [void]
|
|
26
26
|
def copy_config
|
|
27
|
-
template
|
|
27
|
+
template "anyicon.rb", "config/initializers/anyicon.rb"
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -15,4 +15,11 @@ Anyicon.configure do |config|
|
|
|
15
15
|
# }
|
|
16
16
|
# )
|
|
17
17
|
#
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Optional: Set a GitHub personal access token to avoid API rate limits
|
|
21
|
+
# (60 requests/hour unauthenticated vs 5,000/hour authenticated).
|
|
22
|
+
#
|
|
23
|
+
# config.github_token = ENV["GITHUB_TOKEN"]
|
|
24
|
+
#
|
|
18
25
|
end
|
data/lib/tasks/anyicon.rake
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
namespace :anyicon do
|
|
4
|
-
desc
|
|
5
|
-
task :download_collection, [:collection] => :environment do |_t, args|
|
|
4
|
+
desc "Download a specific icon collection"
|
|
5
|
+
task :download_collection, [ :collection ] => :environment do |_t, args|
|
|
6
6
|
collection = args[:collection]
|
|
7
7
|
if Anyicon.configuration.collections.keys.include?(collection.to_sym)
|
|
8
8
|
Anyicon::Collection.new(collection.to_sym).download_all
|
|
@@ -11,9 +11,9 @@ namespace :anyicon do
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
desc
|
|
14
|
+
desc "Download all icon collections"
|
|
15
15
|
task download_all_collections: :environment do
|
|
16
|
-
puts
|
|
16
|
+
puts "Downloading all icon collections"
|
|
17
17
|
Anyicon.configuration.collections.each_key do |collection|
|
|
18
18
|
puts "Downloading #{collection}..."
|
|
19
19
|
Anyicon::Collection.new(collection).download_all
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: anyicon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Arthur Molina
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -24,6 +23,20 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '5.2'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: nokogiri
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
27
40
|
- !ruby/object:Gem::Dependency
|
|
28
41
|
name: appraisal
|
|
29
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -139,7 +152,6 @@ metadata:
|
|
|
139
152
|
source_code_uri: https://github.com/arthurmolina/anyicon
|
|
140
153
|
bug_tracker_uri: https://github.com/arthurmolina/anyicon/issues
|
|
141
154
|
wiki_uri: https://github.com/arthurmolina/anyicon/wiki
|
|
142
|
-
post_install_message:
|
|
143
155
|
rdoc_options: []
|
|
144
156
|
require_paths:
|
|
145
157
|
- lib
|
|
@@ -154,8 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
154
166
|
- !ruby/object:Gem::Version
|
|
155
167
|
version: '0'
|
|
156
168
|
requirements: []
|
|
157
|
-
rubygems_version: 3.
|
|
158
|
-
signing_key:
|
|
169
|
+
rubygems_version: 3.6.9
|
|
159
170
|
specification_version: 4
|
|
160
171
|
summary: Rails View Helpers for any icon collections.
|
|
161
172
|
test_files: []
|