icons 0.8.0 → 0.9.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 +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +17 -0
- data/lib/icons/configuration/boxicons.rb +5 -1
- data/lib/icons/configuration.rb +16 -1
- data/lib/icons/icon/attributes.rb +0 -2
- data/lib/icons/icon/configurable.rb +49 -0
- data/lib/icons/icon/file_path.rb +8 -7
- data/lib/icons/icon.rb +16 -42
- data/lib/icons/libraries.rb +2 -0
- data/lib/icons/sprite/reference.rb +23 -0
- data/lib/icons/sprite.rb +68 -0
- data/lib/icons/sprite_icon.rb +60 -0
- data/lib/icons/sync/process_variants.rb +15 -4
- data/lib/icons/sync/transformations.rb +30 -3
- data/lib/icons/sync.rb +16 -2
- data/lib/icons/version.rb +1 -1
- data/lib/icons.rb +8 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eddb62f576eb4a0f7914cd2fba762e6306bed0fefd719671c9f631a3d4b84644
|
|
4
|
+
data.tar.gz: a108e7b8f54aada59206d3c2a125d4b75c6e05386ac84ca760f13a801d2dbb8d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f6d4f4a1e29efc77f46622ab78b4aa041d7a5116d3c4ec945a610d66f60f8f8cd66266f0cbfcb0b9ccff6d7f4c515c726d69ece0af5bc41c729da31054d4f66
|
|
7
|
+
data.tar.gz: 22dcc6888aa46bf59476e9d511df57d04ff4ff7e5c32230372164f06c8ccd6654e3875a28d2a986874eae162330d1dd581e24e051d861511b7fb4126c3a9e038
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
icons (0.
|
|
4
|
+
icons (0.9.0)
|
|
5
5
|
nokogiri (~> 1.16, >= 1.16.4)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -119,7 +119,7 @@ CHECKSUMS
|
|
|
119
119
|
date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
|
|
120
120
|
debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6
|
|
121
121
|
erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5
|
|
122
|
-
icons (0.
|
|
122
|
+
icons (0.9.0)
|
|
123
123
|
io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
|
|
124
124
|
irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806
|
|
125
125
|
json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505
|
data/README.md
CHANGED
|
@@ -34,6 +34,22 @@ Icons::Sync.new("lucide").now
|
|
|
34
34
|
# Render an icon
|
|
35
35
|
icon = Icons::Icon.new(name: "check", library: "lucide", variant: "outline", arguments: { class: "text-gray-500" })
|
|
36
36
|
svg = icon.svg
|
|
37
|
+
|
|
38
|
+
# Generate SVG sprite for performance
|
|
39
|
+
sprite = Icons::Sprite.new(icons: ["check", "search"], library: "lucide", variant: "outline")
|
|
40
|
+
svg = sprite.svg
|
|
41
|
+
# => <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
|
42
|
+
# <symbol id="lucide_outline_check" viewBox="0 0 24 24">...</symbol>
|
|
43
|
+
# <symbol id="lucide_outline_search" viewBox="0 0 24 24">...</symbol>
|
|
44
|
+
# </svg>
|
|
45
|
+
|
|
46
|
+
# Or configure globally
|
|
47
|
+
Icons.configure do |config|
|
|
48
|
+
config.sprite = { lucide: { outline: ["check", "search"] } }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
sprite = Icons::Sprite.new
|
|
52
|
+
sprite.svg
|
|
37
53
|
```
|
|
38
54
|
|
|
39
55
|
The resulting SVG will include the proper attributes and the SVG content from the library’s asset path.
|
|
@@ -45,6 +61,7 @@ The resulting SVG will include the proper attributes and the SVG content from th
|
|
|
45
61
|
- [Feather](https://railsdesigner.com/open-source/rails-icons/feather/) (280+ icons)
|
|
46
62
|
- [Flags](https://railsdesigner.com/open-source/rails-icons/flags/) (540+ icons)
|
|
47
63
|
- [Heroicons](https://railsdesigner.com/open-source/rails-icons/heroicons/) (300+ icons)
|
|
64
|
+
- [Hugeicons](https://railsdesigner.com/open-source/rails-icons/hugeicons/) (4600+ icons)
|
|
48
65
|
- [Linear](https://railsdesigner.com/open-source/rails-icons/linear/) (170+ icons)
|
|
49
66
|
- [Lucide](https://railsdesigner.com/open-source/rails-icons/lucide/) (1500+ icons)
|
|
50
67
|
- [Phosphor](https://railsdesigner.com/open-source/rails-icons/phosphor/) (9000+ icons)
|
data/lib/icons/configuration.rb
CHANGED
|
@@ -5,7 +5,10 @@ require "icons/configuration/options"
|
|
|
5
5
|
|
|
6
6
|
module Icons
|
|
7
7
|
class Configuration
|
|
8
|
-
|
|
8
|
+
# @return [String, nil]
|
|
9
|
+
attr_accessor :default_library, :icons_path, :default_variant, :sprite, :default_sprite_location, :validate_sprite_icons
|
|
10
|
+
|
|
11
|
+
# @return [Options]
|
|
9
12
|
attr_reader :libraries
|
|
10
13
|
|
|
11
14
|
def initialize
|
|
@@ -15,22 +18,31 @@ module Icons
|
|
|
15
18
|
set_libraries_config
|
|
16
19
|
end
|
|
17
20
|
|
|
21
|
+
# @deprecated Use {#icons_path} instead
|
|
22
|
+
# @return [String]
|
|
23
|
+
#
|
|
18
24
|
def destination_path
|
|
19
25
|
warn "[DEPRECATION] `destination_path` is deprecated. Use `icons_path` instead."
|
|
20
26
|
|
|
21
27
|
@icons_path
|
|
22
28
|
end
|
|
23
29
|
|
|
30
|
+
# @deprecated Use {#icons_path=} instead
|
|
31
|
+
#
|
|
24
32
|
def destination_path=(value)
|
|
25
33
|
warn "[DEPRECATION] `destination_path=` is deprecated. Use `icons_path=` instead."
|
|
26
34
|
|
|
27
35
|
@icons_path = value
|
|
28
36
|
end
|
|
29
37
|
|
|
38
|
+
# @return [Pathname]
|
|
39
|
+
#
|
|
30
40
|
def base_path
|
|
31
41
|
@base_path ||= Pathname.new(Dir.pwd)
|
|
32
42
|
end
|
|
33
43
|
|
|
44
|
+
# @param value [Pathname, String]
|
|
45
|
+
#
|
|
34
46
|
def base_path=(value)
|
|
35
47
|
@base_path = value.is_a?(Pathname) ? value : Pathname.new(value)
|
|
36
48
|
end
|
|
@@ -41,6 +53,9 @@ module Icons
|
|
|
41
53
|
@default_library = nil
|
|
42
54
|
@default_variant = nil
|
|
43
55
|
@icons_path = "app/assets/svg/icons"
|
|
56
|
+
@sprite = {}
|
|
57
|
+
@default_sprite_location = nil
|
|
58
|
+
@validate_sprite_icons = false
|
|
44
59
|
end
|
|
45
60
|
|
|
46
61
|
def set_libraries_config
|
|
@@ -28,7 +28,6 @@ module Icons
|
|
|
28
28
|
def token_list(value)
|
|
29
29
|
case value
|
|
30
30
|
when Array
|
|
31
|
-
# Flatten and process each element
|
|
32
31
|
value.flatten.map { |v|
|
|
33
32
|
if v.is_a?(Hash)
|
|
34
33
|
v.select { |_, val| val }.keys.map(&:to_s).join(" ")
|
|
@@ -37,7 +36,6 @@ module Icons
|
|
|
37
36
|
end
|
|
38
37
|
}.compact.reject(&:empty?).join(" ")
|
|
39
38
|
when Hash
|
|
40
|
-
# Handle both string and symbol keys, filter truthy values
|
|
41
39
|
value.select { |_, v| v }.keys.map(&:to_s).join(" ")
|
|
42
40
|
else
|
|
43
41
|
value.to_s
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icons
|
|
4
|
+
class Icon
|
|
5
|
+
module Configurable
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def set_variant
|
|
9
|
+
value = @config.libraries.dig(@library, :default_variant) || @config.default_variant
|
|
10
|
+
|
|
11
|
+
value.to_s.empty? ? nil : value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def error_message
|
|
15
|
+
attributes = [
|
|
16
|
+
@library,
|
|
17
|
+
@variant,
|
|
18
|
+
@name
|
|
19
|
+
].compact
|
|
20
|
+
|
|
21
|
+
"Icon not found: `#{attributes.join(" / ")}`"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def attach_attributes(to:)
|
|
25
|
+
Icons::Icon::Attributes
|
|
26
|
+
.new(default_attributes: default_attributes, arguments: @arguments)
|
|
27
|
+
.attach(to: to)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def default_attributes
|
|
31
|
+
{
|
|
32
|
+
"stroke-width": default(:stroke_width),
|
|
33
|
+
data: default(:data),
|
|
34
|
+
class: default(:css)
|
|
35
|
+
}.compact
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def default(key)
|
|
39
|
+
library_attributes.dig(:default, key)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def library_attributes
|
|
43
|
+
keys = [@library, @variant].compact
|
|
44
|
+
|
|
45
|
+
@config.libraries.dig(*keys) || {}
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/icons/icon/file_path.rb
CHANGED
|
@@ -7,8 +7,8 @@ module Icons
|
|
|
7
7
|
class FilePath
|
|
8
8
|
def initialize(name:, library:, variant:)
|
|
9
9
|
@name = name
|
|
10
|
-
@library = library.
|
|
11
|
-
@variant = variant
|
|
10
|
+
@library = library.to_sym
|
|
11
|
+
@variant = variant&.to_sym
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def call
|
|
@@ -26,7 +26,7 @@ module Icons
|
|
|
26
26
|
private
|
|
27
27
|
|
|
28
28
|
def animated_library?
|
|
29
|
-
@library ==
|
|
29
|
+
@library == :animated
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def animated_icons_path
|
|
@@ -39,11 +39,12 @@ module Icons
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def custom_library?
|
|
42
|
-
Icons.libraries[@library
|
|
42
|
+
Icons.libraries[@library]&.respond_to?(:custom_path)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def custom_library_path
|
|
46
|
-
library_config = Icons.libraries[@library
|
|
46
|
+
library_config = Icons.libraries[@library]
|
|
47
|
+
|
|
47
48
|
Icons.config.base_path.join(library_config.custom_path, "#{@name}.svg")
|
|
48
49
|
end
|
|
49
50
|
|
|
@@ -54,8 +55,8 @@ module Icons
|
|
|
54
55
|
def parts
|
|
55
56
|
[
|
|
56
57
|
Icons.configuration.icons_path,
|
|
57
|
-
@library,
|
|
58
|
-
(@variant unless @variant == "."),
|
|
58
|
+
@library.to_s,
|
|
59
|
+
(@variant&.to_s unless @variant == :"."), # Don't include "." as a directory
|
|
59
60
|
"#{@name}.svg"
|
|
60
61
|
].compact.reject { |p| p.to_s.empty? }
|
|
61
62
|
end
|
data/lib/icons/icon.rb
CHANGED
|
@@ -4,17 +4,31 @@ require "nokogiri"
|
|
|
4
4
|
|
|
5
5
|
require "icons/icon/file_path"
|
|
6
6
|
require "icons/icon/attributes"
|
|
7
|
+
require "icons/icon/configurable"
|
|
7
8
|
|
|
8
9
|
class Icons::Icon
|
|
10
|
+
include Icons::Icon::Configurable
|
|
11
|
+
|
|
12
|
+
# @param name [String] The icon name
|
|
13
|
+
# @param library [String, Symbol] The icon library
|
|
14
|
+
# @param variant [String, Symbol, nil] The icon variant (optional)
|
|
15
|
+
# @param arguments [Hash] Additional attributes including class, data, stroke_width, etc.
|
|
16
|
+
#
|
|
9
17
|
def initialize(name:, library:, arguments:, variant: nil)
|
|
10
18
|
@config = Icons.configuration
|
|
11
19
|
|
|
12
20
|
@name = name
|
|
13
|
-
@library = library.
|
|
14
|
-
@variant = (variant || set_variant)
|
|
21
|
+
@library = library.to_sym
|
|
22
|
+
@variant = (variant || set_variant)&.to_sym
|
|
15
23
|
@arguments = arguments
|
|
16
24
|
end
|
|
17
25
|
|
|
26
|
+
# Returns the rendered SVG markup for the icon
|
|
27
|
+
#
|
|
28
|
+
# @return [String] The SVG markup as an HTML string
|
|
29
|
+
#
|
|
30
|
+
# @raise [Icons::IconNotFound] If the icon file does not exist
|
|
31
|
+
#
|
|
18
32
|
def svg
|
|
19
33
|
Nokogiri::HTML::DocumentFragment.parse(File.read(file_path))
|
|
20
34
|
.at_css("svg")
|
|
@@ -26,47 +40,7 @@ class Icons::Icon
|
|
|
26
40
|
|
|
27
41
|
private
|
|
28
42
|
|
|
29
|
-
def set_variant
|
|
30
|
-
value = @config.libraries.dig(@library.to_sym, :default_variant) ||
|
|
31
|
-
@config.default_variant
|
|
32
|
-
|
|
33
|
-
value.to_s.empty? ? nil : value
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def error_message
|
|
37
|
-
attributes = [
|
|
38
|
-
@library,
|
|
39
|
-
@variant,
|
|
40
|
-
@name
|
|
41
|
-
].compact
|
|
42
|
-
|
|
43
|
-
"Icon not found: `#{attributes.join(" / ")}`"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
43
|
def file_path
|
|
47
44
|
Icons::Icon::FilePath.new(name: @name, library: @library, variant: @variant).call
|
|
48
45
|
end
|
|
49
|
-
|
|
50
|
-
def attach_attributes(to:)
|
|
51
|
-
Icons::Icon::Attributes
|
|
52
|
-
.new(default_attributes: default_attributes, arguments: @arguments)
|
|
53
|
-
.attach(to: to)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def default_attributes
|
|
57
|
-
{
|
|
58
|
-
"stroke-width": default(:stroke_width),
|
|
59
|
-
data: default(:data),
|
|
60
|
-
class: default(:css)
|
|
61
|
-
}
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def default(key)
|
|
65
|
-
library_attributes.dig(:default, key)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def library_attributes
|
|
69
|
-
keys = [@library, @variant].compact.reject { |k| k.to_s.empty? }
|
|
70
|
-
@config.libraries.dig(*keys) || {}
|
|
71
|
-
end
|
|
72
46
|
end
|
data/lib/icons/libraries.rb
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icons
|
|
4
|
+
class Sprite
|
|
5
|
+
Reference = Data.define(:name, :library, :variant) do
|
|
6
|
+
def id = [library, variant, name].join("_")
|
|
7
|
+
|
|
8
|
+
def file_path
|
|
9
|
+
Icons::Icon::FilePath.new(
|
|
10
|
+
name: name.to_s,
|
|
11
|
+
library: library.to_s,
|
|
12
|
+
variant: variant.to_s
|
|
13
|
+
).call
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def exists?
|
|
17
|
+
File.exist?(file_path)
|
|
18
|
+
rescue Icons::IconNotFound
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/icons/sprite.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icons
|
|
4
|
+
class Sprite
|
|
5
|
+
# @param config [Configuration] The configuration object (defaults to Icons.configuration)
|
|
6
|
+
# @param icons [Array<String>, nil] Optional list of icon names to include (defaults to configured icons)
|
|
7
|
+
# @param library [String, Symbol, nil] The icon library to use when icons are provided
|
|
8
|
+
# @param variant [String, Symbol, nil] The icon variant to use when icons are provided
|
|
9
|
+
#
|
|
10
|
+
def initialize(config: Icons.configuration, icons: nil, library: nil, variant: nil)
|
|
11
|
+
@config = config
|
|
12
|
+
@icons = icons
|
|
13
|
+
@library = library
|
|
14
|
+
@variant = variant
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns the combined SVG sprite markup containing all icon symbols
|
|
18
|
+
#
|
|
19
|
+
# @return [String] The SVG markup with `<symbol>` elements wrapped in a hidden `<svg>`
|
|
20
|
+
#
|
|
21
|
+
def svg
|
|
22
|
+
symbols = references.filter_map { |reference| symbol_from(reference) }
|
|
23
|
+
|
|
24
|
+
<<~SVG
|
|
25
|
+
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
|
26
|
+
#{symbols.join("\n ")}
|
|
27
|
+
</svg>
|
|
28
|
+
SVG
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def references
|
|
34
|
+
@icons ? override_references : configured_references
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def override_references
|
|
38
|
+
library = @library || @config.default_library
|
|
39
|
+
variant = @variant || @config.default_variant
|
|
40
|
+
|
|
41
|
+
@icons.map { |name| Sprite::Reference.new(name: name, library: library, variant: variant) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def configured_references
|
|
45
|
+
sprite_config = @config.sprite || {}
|
|
46
|
+
|
|
47
|
+
sprite_config.flat_map do |library, variants|
|
|
48
|
+
variants.flat_map do |variant, names|
|
|
49
|
+
names.map { |name| Sprite::Reference.new(name: name, library: library, variant: variant) }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def symbol_from(reference)
|
|
55
|
+
return unless reference.exists?
|
|
56
|
+
|
|
57
|
+
svg_element = Nokogiri::XML(File.read(reference.file_path)).at_css("svg")
|
|
58
|
+
view_box = svg_element["viewBox"] || "0 0 24 24"
|
|
59
|
+
content = svg_element.children.map(&:to_s).join
|
|
60
|
+
|
|
61
|
+
%(<symbol id="#{reference.id}" viewBox="#{view_box}">#{content}</symbol>)
|
|
62
|
+
rescue Icons::IconNotFound
|
|
63
|
+
warn "Icon not found: #{reference.name} from #{reference.library}/#{reference.variant}"
|
|
64
|
+
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
|
|
5
|
+
require "icons/icon/attributes"
|
|
6
|
+
require "icons/icon/configurable"
|
|
7
|
+
|
|
8
|
+
class Icons::SpriteIcon
|
|
9
|
+
include Icons::Icon::Configurable
|
|
10
|
+
|
|
11
|
+
# @param name [String] The icon name
|
|
12
|
+
# @param library [String, Symbol] The icon library
|
|
13
|
+
# @param variant [String, Symbol, nil] The icon variant (optional)
|
|
14
|
+
# @param arguments [Hash] Additional attributes including class, data, stroke_width, etc.
|
|
15
|
+
# @param sprite_location [String, nil] Override URL for the sprite file (optional)
|
|
16
|
+
# @param config [Configuration] The configuration object (defaults to Icons.configuration)
|
|
17
|
+
#
|
|
18
|
+
def initialize(name:, library:, arguments:, variant: nil, sprite_location: nil, config: Icons.configuration)
|
|
19
|
+
@config = config
|
|
20
|
+
|
|
21
|
+
@name = name
|
|
22
|
+
@library = library.to_sym
|
|
23
|
+
@variant = (variant || set_variant)&.to_sym
|
|
24
|
+
@arguments = arguments
|
|
25
|
+
@sprite_location = sprite_location || @config.default_sprite_location
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns the SVG markup referencing the icon from a sprite sheet
|
|
29
|
+
#
|
|
30
|
+
# @return [String] The SVG markup using a `<use>` tag referencing the sprite symbol
|
|
31
|
+
#
|
|
32
|
+
# @raise [Icons::IconNotFound] If validate_sprite_icons is enabled and the icon does not exist
|
|
33
|
+
#
|
|
34
|
+
def svg
|
|
35
|
+
if @config.validate_sprite_icons
|
|
36
|
+
raise Icons::IconNotFound, error_message unless reference.exists?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
sprite_svg
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def reference
|
|
45
|
+
@reference ||= Icons::Sprite::Reference.new(name: @name, library: @library, variant: @variant)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def sprite_svg
|
|
49
|
+
sprite_href = @sprite_location.nil? ? "##{reference.id}" : "#{@sprite_location}##{reference.id}"
|
|
50
|
+
|
|
51
|
+
svg_content = <<~SVG
|
|
52
|
+
<svg><use href="#{sprite_href}"></use></svg>
|
|
53
|
+
SVG
|
|
54
|
+
|
|
55
|
+
Nokogiri::HTML::DocumentFragment.parse(svg_content)
|
|
56
|
+
.at_css("svg")
|
|
57
|
+
.tap { |svg| attach_attributes(to: svg) }
|
|
58
|
+
.to_html
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -47,10 +47,13 @@ module Icons
|
|
|
47
47
|
|
|
48
48
|
def apply_transformations_to(destination)
|
|
49
49
|
Dir.each_child(destination) do |filename|
|
|
50
|
-
File.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
original_file_path = File.join(destination, filename)
|
|
51
|
+
transformed_filename = Sync::Transformations.transform(filename, transformations)
|
|
52
|
+
transformed_file_path = File.join(destination, transformed_filename)
|
|
53
|
+
|
|
54
|
+
File.rename(original_file_path, transformed_file_path)
|
|
55
|
+
|
|
56
|
+
transform_svg(transformed_file_path)
|
|
54
57
|
end
|
|
55
58
|
end
|
|
56
59
|
|
|
@@ -75,6 +78,14 @@ module Icons
|
|
|
75
78
|
{}
|
|
76
79
|
end
|
|
77
80
|
end
|
|
81
|
+
|
|
82
|
+
def transform_svg(file_path)
|
|
83
|
+
return if File.extname(file_path) != ".svg"
|
|
84
|
+
|
|
85
|
+
svg_transformations = transformations.fetch(:svg, [])
|
|
86
|
+
|
|
87
|
+
Sync::Transformations.transform_svg(file_path, svg_transformations)
|
|
88
|
+
end
|
|
78
89
|
end
|
|
79
90
|
end
|
|
80
91
|
end
|
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
|
|
3
5
|
module Icons
|
|
4
6
|
class Sync
|
|
5
7
|
class Transformations
|
|
6
8
|
def self.transform(filename, rules = {})
|
|
7
9
|
basename = File.basename(filename, File.extname(filename))
|
|
8
10
|
|
|
9
|
-
transformed = rules.reduce(basename) do |fn, (type, value)|
|
|
10
|
-
|
|
11
|
+
transformed = rules.fetch(:filenames, {}).reduce(basename) do |fn, (type, value)|
|
|
12
|
+
FILENAME_TRANSFORMERS.fetch(type).call(fn, value)
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
[transformed, File.extname(filename)].join
|
|
14
16
|
end
|
|
15
17
|
|
|
18
|
+
def self.transform_svg(file_path, rules = [])
|
|
19
|
+
return unless rules.any?
|
|
20
|
+
|
|
21
|
+
svg_document = Nokogiri::HTML::DocumentFragment.parse(File.read(file_path))
|
|
22
|
+
|
|
23
|
+
rules.each do |rule|
|
|
24
|
+
SVG_TRANSFORMERS.fetch(rule[:action]).call(
|
|
25
|
+
svg_document,
|
|
26
|
+
rule[:element],
|
|
27
|
+
rule[:attribute],
|
|
28
|
+
rule[:value]
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
File.write(file_path, svg_document.to_html)
|
|
33
|
+
end
|
|
34
|
+
|
|
16
35
|
private
|
|
17
36
|
|
|
18
|
-
|
|
37
|
+
FILENAME_TRANSFORMERS = {
|
|
19
38
|
delete_prefix: ->(filename, prefixes) {
|
|
20
39
|
Array(prefixes).reduce(filename) { |fn, prefix| fn.delete_prefix(prefix) }
|
|
21
40
|
},
|
|
@@ -24,6 +43,14 @@ module Icons
|
|
|
24
43
|
Array(suffixes).reduce(filename) { |fn, suffix| fn.delete_suffix(suffix) }
|
|
25
44
|
}
|
|
26
45
|
}
|
|
46
|
+
|
|
47
|
+
SVG_TRANSFORMERS = {
|
|
48
|
+
set_attribute: ->(document, element_selector, attribute_name, attribute_value) {
|
|
49
|
+
document.css(element_selector).each do |element|
|
|
50
|
+
element[attribute_name] = attribute_value
|
|
51
|
+
end
|
|
52
|
+
}
|
|
53
|
+
}
|
|
27
54
|
end
|
|
28
55
|
end
|
|
29
56
|
end
|
data/lib/icons/sync.rb
CHANGED
|
@@ -6,7 +6,7 @@ require "icons/sync/process_variants"
|
|
|
6
6
|
module Icons
|
|
7
7
|
class Sync
|
|
8
8
|
def initialize(name)
|
|
9
|
-
raise "[Icons] Not a valid library"
|
|
9
|
+
raise "[Icons] Not a valid library" unless Icons.libraries.key?(name.to_sym)
|
|
10
10
|
|
|
11
11
|
@name = name
|
|
12
12
|
@library = Icons.libraries.fetch(name.to_sym).source
|
|
@@ -36,11 +36,25 @@ module Icons
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def clone_repository
|
|
39
|
-
|
|
39
|
+
unless clone_repository_sparse
|
|
40
|
+
puts "[Icons] Sparse clone failed, falling back to full clone"
|
|
41
|
+
FileUtils.rm_rf(@temp_directory)
|
|
42
|
+
|
|
43
|
+
raise "[Icons] Failed to clone repository" unless system("git clone '#{@library[:url]}' '#{@temp_directory}'")
|
|
44
|
+
end
|
|
40
45
|
|
|
41
46
|
puts "[Icons] '#{@name}' repository cloned"
|
|
42
47
|
end
|
|
43
48
|
|
|
49
|
+
def clone_repository_sparse
|
|
50
|
+
system("git clone --depth 1 --filter=blob:none --sparse '#{@library[:url]}' '#{@temp_directory}'") &&
|
|
51
|
+
system("git -C '#{@temp_directory}' sparse-checkout set #{sparse_checkout_paths}")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def sparse_checkout_paths
|
|
55
|
+
@library[:variants].values.map { |path| "'#{path}'" }.join(" ")
|
|
56
|
+
end
|
|
57
|
+
|
|
44
58
|
def process_variants
|
|
45
59
|
Sync::ProcessVariants.new(@temp_directory, @name, @library).process
|
|
46
60
|
end
|
data/lib/icons/version.rb
CHANGED
data/lib/icons.rb
CHANGED
|
@@ -5,17 +5,25 @@ require "icons/errors"
|
|
|
5
5
|
require "icons/libraries"
|
|
6
6
|
require "icons/configuration"
|
|
7
7
|
require "icons/icon"
|
|
8
|
+
require "icons/sprite/reference"
|
|
9
|
+
require "icons/sprite"
|
|
8
10
|
require "icons/sync"
|
|
9
11
|
|
|
10
12
|
module Icons
|
|
11
13
|
class << self
|
|
14
|
+
# @return [Configuration]
|
|
12
15
|
attr_accessor :configuration
|
|
13
16
|
|
|
17
|
+
# @yield [config] Yields the configuration object for customization
|
|
18
|
+
# @yieldparam config [Configuration]
|
|
19
|
+
#
|
|
14
20
|
def configure
|
|
15
21
|
self.configuration ||= Configuration.new
|
|
16
22
|
yield(configuration) if block_given?
|
|
17
23
|
end
|
|
18
24
|
|
|
25
|
+
# @return [Configuration]
|
|
26
|
+
#
|
|
19
27
|
def config
|
|
20
28
|
configuration || configure {}
|
|
21
29
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: icons
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rails Designer
|
|
@@ -67,8 +67,12 @@ files:
|
|
|
67
67
|
- lib/icons/errors.rb
|
|
68
68
|
- lib/icons/icon.rb
|
|
69
69
|
- lib/icons/icon/attributes.rb
|
|
70
|
+
- lib/icons/icon/configurable.rb
|
|
70
71
|
- lib/icons/icon/file_path.rb
|
|
71
72
|
- lib/icons/libraries.rb
|
|
73
|
+
- lib/icons/sprite.rb
|
|
74
|
+
- lib/icons/sprite/reference.rb
|
|
75
|
+
- lib/icons/sprite_icon.rb
|
|
72
76
|
- lib/icons/sync.rb
|
|
73
77
|
- lib/icons/sync/process_variants.rb
|
|
74
78
|
- lib/icons/sync/transformations.rb
|
|
@@ -93,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
93
97
|
- !ruby/object:Gem::Version
|
|
94
98
|
version: '0'
|
|
95
99
|
requirements: []
|
|
96
|
-
rubygems_version: 4.0.
|
|
100
|
+
rubygems_version: 4.0.14
|
|
97
101
|
specification_version: 4
|
|
98
102
|
summary: Add any icon library to a Ruby app
|
|
99
103
|
test_files: []
|