icons 0.9.0 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eddb62f576eb4a0f7914cd2fba762e6306bed0fefd719671c9f631a3d4b84644
4
- data.tar.gz: a108e7b8f54aada59206d3c2a125d4b75c6e05386ac84ca760f13a801d2dbb8d
3
+ metadata.gz: b3020899914efdd03ecf2a92102d477b2f8852aa3688ea09039aaf6d220c0e67
4
+ data.tar.gz: ab8d18495924688b6797bf9c8cc17fb11b0ed2789915dc93cf39fdaf15ae76fd
5
5
  SHA512:
6
- metadata.gz: 2f6d4f4a1e29efc77f46622ab78b4aa041d7a5116d3c4ec945a610d66f60f8f8cd66266f0cbfcb0b9ccff6d7f4c515c726d69ece0af5bc41c729da31054d4f66
7
- data.tar.gz: 22dcc6888aa46bf59476e9d511df57d04ff4ff7e5c32230372164f06c8ccd6654e3875a28d2a986874eae162330d1dd581e24e051d861511b7fb4126c3a9e038
6
+ metadata.gz: 1bac607ff06f7a74a61ad368de35962f29b159d57be17d1181f2a38471fc5c0a6563955015f25690267e41d88acec1344192409d41df0d984617a07c9ac57297
7
+ data.tar.gz: 956af529c206586d7d30d9558e5c36545f2805c5d9a6187eef508e9efa6282ebcd10bca1f1b856186a2a55fd293bd7f6edb5b4ae48c68977dd5951a2693c95c0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- icons (0.9.0)
4
+ icons (0.11.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.9.0)
122
+ icons (0.11.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
@@ -5,7 +5,7 @@ Add any icon library to a Ruby app. Icons has first-party support for a [dozen o
5
5
 
6
6
  ## Installation
7
7
 
8
- Add the core gem to your Gemfile:
8
+ Add the core gem to the Gemfile:
9
9
  ```ruby
10
10
  gem "icons"
11
11
  ```
@@ -55,6 +55,60 @@ sprite.svg
55
55
  The resulting SVG will include the proper attributes and the SVG content from the library’s asset path.
56
56
 
57
57
 
58
+ ## Custom libraries
59
+
60
+ Add non first-party icon libraries. The Icons gem looks for SVGs at `<icons_path>/<library_name>/<name>.svg`, so any name works without configuration.
61
+
62
+
63
+ ### Zero config
64
+
65
+ Place SVGs at the expected path:
66
+ ```bash
67
+ app/assets/svg/icons/my_icons/check.svg
68
+ ```
69
+
70
+ Usage:
71
+ ```ruby
72
+ Icons::Icon.new(name: "check", library: "my_icons", arguments: {}).svg
73
+ ```
74
+
75
+
76
+ ### Registered custom libraries
77
+
78
+ Use `config.custom_library` to declare a custom library with defaults:
79
+ ```ruby
80
+ Icons.configure do |config|
81
+ config.custom_library :my_icons
82
+ end
83
+ ```
84
+
85
+ Then set library specific defaults:
86
+ ```ruby
87
+ Icons.configure do |config|
88
+ config.custom_library :my_icons
89
+
90
+ config.libraries.my_icons.default.css = "size-6"
91
+ config.libraries.my_icons.default.stroke_width = 1.5
92
+ end
93
+ ```
94
+
95
+ ### Custom libraries with a git source
96
+
97
+ Pass a `source:` option to make a custom library syncable from a Git repository:
98
+ ```ruby
99
+ Icons.configure do |config|
100
+ config.custom_library :my_icons, source: {
101
+ url: "https://github.com/user/icons.git",
102
+ variants: { default: "." }
103
+ }
104
+ end
105
+
106
+ Icons::Sync.new(:my_icons).now
107
+ ```
108
+
109
+ After syncing, `Icons::Icon.new(name: "check", library: "my_icons", arguments: {}).svg` , works just like any first party library.
110
+
111
+
58
112
  ## First-party libraries
59
113
 
60
114
  - [Boxicons](https://railsdesigner.com/open-source/rails-icons/boxicons/) (1600+ icons)
data/icons.gemspec CHANGED
@@ -18,5 +18,7 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.files = Dir["{bin,config,lib}/**/*", "Rakefile", "README.md", "icons.gemspec", "Gemfile", "Gemfile.lock"]
20
20
 
21
+ spec.required_ruby_version = ">= 3.1.0"
22
+
21
23
  spec.add_runtime_dependency "nokogiri", "~> 1.16", ">= 1.16.4"
22
24
  end
@@ -23,6 +23,7 @@ module Icons
23
23
  # Override Boxicons defaults
24
24
  # config.libraries.boxicons.default_variant = "" # Set a default variant for Boxicons
25
25
  # config.libraries.boxicons.exclude_variants = [] # Exclude specific variants
26
+ # config.libraries.boxicons.variants = [] # Only sync these variants
26
27
 
27
28
  # config.libraries.boxicons.solid.css = "size-6"
28
29
  # config.libraries.boxicons.solid.data = {}
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Icons
4
+ class Configuration
5
+ class CustomLibrary
6
+ attr_reader :source
7
+
8
+ def initialize(source: nil)
9
+ @source = source
10
+ end
11
+
12
+ def config
13
+ Options.new.tap do |options|
14
+ options.default_variant = nil
15
+ options.exclude_variants = []
16
+ end
17
+ end
18
+
19
+ def initializer_config
20
+ ""
21
+ end
22
+ end
23
+ end
24
+ end
@@ -21,6 +21,7 @@ module Icons
21
21
  # Override Feather defaults
22
22
  # config.libraries.feather.default_variant = "" # Feather has no variants, this is provided for backwards compatibility
23
23
  # config.libraries.feather.exclude_variants = [] # Feather has no variants, this is provided for backwards compatibility
24
+ # config.libraries.feather.variants = [] # Feather has no variants, provided for consistency
24
25
 
25
26
  # config.libraries.feather.default.css = "size-6"
26
27
  # config.libraries.feather.default.stroke_width = "2"
@@ -22,6 +22,7 @@ module Icons
22
22
  # Override Flags defaults
23
23
  # config.libraries.flags.default_variant = "" # Set a default variant for Flags
24
24
  # config.libraries.flags.exclude_variants = [:square, :landscape]
25
+ # config.libraries.flags.variants = [] # Only sync these variants
25
26
 
26
27
  # config.libraries.flags.square.default.css = "size-6"
27
28
  # config.libraries.flags.square.default.data = {}
@@ -24,6 +24,7 @@ module Icons
24
24
  # Override Heroicon defaults
25
25
  # config.libraries.heroicons.default_variant = "" # Set a default variant for Heroicons
26
26
  # config.libraries.heroicons.exclude_variants = [:mini, :micro] # Exclude specific variants
27
+ # config.libraries.heroicons.variants = [] # Only sync these variants
27
28
 
28
29
  # config.libraries.heroicons.outline.default.css = "size-6"
29
30
  # config.libraries.heroicons.outline.default.stroke_width = "1.5"
@@ -21,6 +21,7 @@ module Icons
21
21
  # Override Hugeicons defaults
22
22
  # config.libraries.hugeicons.default_variant = "" # Hugeicons has no variants, this is provided for backwards compatibility
23
23
  # config.libraries.hugeicons.exclude_variants = [] # Hugeicons has no variants, this is provided for backwards compatibility
24
+ # config.libraries.hugeicons.variants = [] # Hugeicons has no variants, provided for consistency
24
25
 
25
26
  # config.libraries.hugeicons.default.css = "size-6"
26
27
  # config.libraries.hugeicons.default.stroke_width = "1.5"
@@ -21,6 +21,7 @@ module Icons
21
21
  # Override Linear defaults
22
22
  # config.libraries.linear.default_variant = "" # Set a default variant for Linear
23
23
  # config.libraries.linear.exclude_variants = []
24
+ # config.libraries.linear.variants = [] # Linear has no variants, provided for consistency
24
25
 
25
26
  # config.libraries.linear.default.css = "size-6"
26
27
  # config.libraries.linear.default.stroke_width = "2"
@@ -21,6 +21,7 @@ module Icons
21
21
  # Override Lucide defaults
22
22
  # config.libraries.lucide.default_variant = "" # Set a default variant for Lucide
23
23
  # config.libraries.lucide.exclude_variants = [] # Exclude specific variants
24
+ # config.libraries.lucide.variants = [] # Only sync these variants
24
25
 
25
26
  # config.libraries.lucide.outline.default.css = "size-6"
26
27
  # config.libraries.lucide.outline.default.stroke_width = "1.5"
@@ -26,6 +26,7 @@ module Icons
26
26
  # Override Phosphor defaults
27
27
  # config.libraries.phosphor.default_variant = "" # Set a default variant for Phosphor
28
28
  # config.libraries.phosphor.exclude_variants = [:duotone, :thin] # Exclude specific variants
29
+ # config.libraries.phosphor.variants = [] # Only sync these variants
29
30
 
30
31
  # config.libraries.phosphor.bold.default.css = "size-6"
31
32
  # config.libraries.phosphor.bold.default.data = {}
@@ -21,6 +21,8 @@ module Icons
21
21
  # Override Radix defaults
22
22
  # config.libraries.radix.default_variant = "" # Radix has no variants, this is provided for backwards compatibility
23
23
  # config.libraries.radix.exclude_variants = [] # Radix has no variants, this is provided for backwards compatibility
24
+ # config.libraries.radix.variants = [] # Radix has no variants, provided for consistency
25
+
24
26
  # config.libraries.radix.default.css = "size-6"
25
27
  # config.libraries.radix.default.stroke_width = "2"
26
28
  # config.libraries.radix.default.data = {}
@@ -24,6 +24,7 @@ module Icons
24
24
  # Override Sidekickicons defaults
25
25
  # config.libraries.sidekickicons.default_variant = "" # Set a default variant for Sidekickicons
26
26
  # config.libraries.sidekickicons.exclude_variants = [:mini, :micro] # Exclude specific variants
27
+ # config.libraries.sidekickicons.variants = [] # Only sync these variants
27
28
 
28
29
  # config.libraries.sidekickicons.outline.default.css = "size-6"
29
30
  # config.libraries.sidekickicons.outline.default.stroke_width = "1.5"
@@ -22,6 +22,7 @@ module Icons
22
22
  # Override Tabler defaults
23
23
  # config.libraries.tabler.default_variant = "" # Set a default variant for Tabler
24
24
  # config.libraries.tabler.exclude_variants = [] # Exclude specific variants
25
+ # config.libraries.tabler.variants = [] # Only sync these variants
25
26
 
26
27
  # config.libraries.tabler.regular.default.css = "size-6"
27
28
  # config.libraries.tabler.solid.default.css = "size-6"
@@ -21,6 +21,7 @@ module Icons
21
21
  # Override Weather defaults
22
22
  # config.libraries.weather.default_variant = "" # Set a default variant for Wweather
23
23
  # config.libraries.weather.exclude_variants = []
24
+ # config.libraries.weather.variants = [] # Only sync these variants
24
25
 
25
26
  # config.libraries.weather.default.css = "size-6"
26
27
  # config.libraries.weather.default.data = {}
@@ -47,6 +47,32 @@ module Icons
47
47
  @base_path = value.is_a?(Pathname) ? value : Pathname.new(value)
48
48
  end
49
49
 
50
+ # Register a custom library at configuration time.
51
+ #
52
+ # @param name [Symbol] The library name used in `icon "name", library: :your_name`
53
+ # @param source [Hash, nil] Optional git source hash with `:url` and `:variants`.
54
+ # When provided, the library becomes syncable via `Icons::Sync.new(:your_name).now`.
55
+ #
56
+ # @example Add a local custom library
57
+ # Icons.configure do |config|
58
+ # config.custom_library :my_icons
59
+ # end
60
+ #
61
+ # @example Add a custom library with a git source
62
+ # Icons.configure do |config|
63
+ # config.custom_library :my_icons, source: { url: "https://github.com/user/icons.git", variants: { default: "." } }
64
+ # end
65
+ #
66
+ def custom_library(name, source: nil)
67
+ name = name.to_sym
68
+
69
+ library_config = CustomLibrary.new(source: source)
70
+
71
+ Icons.register_library(name, library_config)
72
+
73
+ @libraries[name] = library_config.config
74
+ end
75
+
50
76
  private
51
77
 
52
78
  def set_default_config
data/lib/icons/errors.rb CHANGED
@@ -4,7 +4,7 @@ module Icons
4
4
  class IconNotFound < StandardError
5
5
  def initialize(icon_name = nil)
6
6
  if icon_name
7
- super("The icon `#{icon_name}` is not available. Please check the icon name and try again.")
7
+ super("The icon `#{icon_name}` is not available. Check the icon name and try again.")
8
8
  else
9
9
  super("Icon not found")
10
10
  end
@@ -12,12 +12,12 @@ module Icons
12
12
  end
13
13
 
14
14
  class LibraryNotFound < StandardError
15
- def initialize(library_name)
16
- if library_name.empty?
17
- libraries = Icons.libraries.keys.join(", ")
18
- super("No libraries were specified. Please choose from: #{libraries}")
15
+ def initialize(library_name = nil)
16
+ if library_name
17
+ super("The library `#{library_name}` is not available. Check the library name and try again.")
19
18
  else
20
- super("The library `#{library_name}` is not available. Please check the library name and try again.")
19
+ libraries = Icons.libraries.keys.join(", ")
20
+ super("No libraries were specified. Choose from: #{libraries}")
21
21
  end
22
22
  end
23
23
  end
@@ -12,6 +12,8 @@ module Icons
12
12
  end
13
13
 
14
14
  def call
15
+ validate_components!
16
+
15
17
  if animated_library?
16
18
  path = animated_icons_path
17
19
  raise Icons::IconNotFound if path.nil?
@@ -25,6 +27,18 @@ module Icons
25
27
 
26
28
  private
27
29
 
30
+ ALLOWED_CHARACTERS = /\A[a-zA-Z0-9_-]+\z/
31
+
32
+ def validate_components!
33
+ raise Icons::IconNotFound, @name unless safe?(@name.to_s)
34
+ raise Icons::IconNotFound, @name unless safe?(@library.to_s)
35
+ raise Icons::IconNotFound, @name unless @variant.nil? || @variant == :"." || safe?(@variant.to_s)
36
+ end
37
+
38
+ def safe?(component)
39
+ component.match?(ALLOWED_CHARACTERS)
40
+ end
41
+
28
42
  def animated_library?
29
43
  @library == :animated
30
44
  end
data/lib/icons/icon.rb CHANGED
@@ -30,11 +30,13 @@ class Icons::Icon
30
30
  # @raise [Icons::IconNotFound] If the icon file does not exist
31
31
  #
32
32
  def svg
33
- Nokogiri::HTML::DocumentFragment.parse(File.read(file_path))
34
- .at_css("svg")
35
- .tap { |svg| attach_attributes(to: svg) }
36
- .to_html
37
- rescue Errno::ENOENT
33
+ svg = Nokogiri::HTML::DocumentFragment.parse(File.read(file_path)).at_css("svg")
34
+ raise Icons::IconNotFound, error_message unless svg
35
+
36
+ attach_attributes(to: svg)
37
+
38
+ svg.to_html
39
+ rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR
38
40
  raise Icons::IconNotFound, error_message
39
41
  end
40
42
 
@@ -15,22 +15,40 @@ require "icons/configuration/weather"
15
15
  module Icons
16
16
  extend self
17
17
 
18
+ BUILT_IN_LIBRARIES = {
19
+ boxicons: Icons::Configuration::Boxicons,
20
+ feather: Icons::Configuration::Feather,
21
+ flags: Icons::Configuration::Flags,
22
+ heroicons: Icons::Configuration::Heroicons,
23
+ hugeicons: Icons::Configuration::Hugeicons,
24
+ linear: Icons::Configuration::Linear,
25
+ lucide: Icons::Configuration::Lucide,
26
+ phosphor: Icons::Configuration::Phosphor,
27
+ radix: Icons::Configuration::Radix,
28
+ sidekickicons: Icons::Configuration::Sidekickicons,
29
+ tabler: Icons::Configuration::Tabler,
30
+ weather: Icons::Configuration::Weather
31
+ }.freeze
32
+
18
33
  # @return [Hash{Symbol => Class}] A map of library names to their configuration classes
19
34
  #
20
35
  def libraries
21
- {
22
- boxicons: Icons::Configuration::Boxicons,
23
- feather: Icons::Configuration::Feather,
24
- flags: Icons::Configuration::Flags,
25
- heroicons: Icons::Configuration::Heroicons,
26
- hugeicons: Icons::Configuration::Hugeicons,
27
- linear: Icons::Configuration::Linear,
28
- lucide: Icons::Configuration::Lucide,
29
- phosphor: Icons::Configuration::Phosphor,
30
- radix: Icons::Configuration::Radix,
31
- sidekickicons: Icons::Configuration::Sidekickicons,
32
- tabler: Icons::Configuration::Tabler,
33
- weather: Icons::Configuration::Weather
34
- }
36
+ BUILT_IN_LIBRARIES.merge(@registered_libraries || {})
37
+ end
38
+
39
+ # Register a custom library for use with the icons gem.
40
+ #
41
+ # @param name [Symbol] The library name
42
+ # @param library_module [Module, Object] A configuration module or object
43
+ # that responds to `.config` and optionally `.source` and `.custom_path`
44
+ #
45
+ def register_library(name, library_module)
46
+ @registered_libraries ||= {}
47
+
48
+ @registered_libraries[name.to_sym] = library_module
49
+ end
50
+
51
+ def reset_registered_libraries
52
+ @registered_libraries = {}
35
53
  end
36
54
  end
@@ -6,17 +6,19 @@ require "icons/sync/transformations"
6
6
  module Icons
7
7
  class Sync
8
8
  class ProcessVariants
9
- def initialize(temp_directory, name, library)
10
- @temp_directory, @name, @library = temp_directory, name, library
9
+ def initialize(temp_directory, name, library, variants: nil)
10
+ @temp_directory = temp_directory
11
+ @name = name
12
+ @library = library
13
+ @variants = variants
11
14
  end
12
15
 
13
16
  def process
14
17
  original_variants = Dir.children(@temp_directory)
15
18
  excluded_variants = Icons.configuration.libraries.dig(@name.to_sym)&.exclude_variants || []
19
+ effective_variants = (@variants || @library[:variants].keys) - excluded_variants
16
20
 
17
- @library[:variants].each do |variant_name, variant_source_path|
18
- next if excluded_variants.include?(variant_name)
19
-
21
+ @library[:variants].slice(*effective_variants).each do |variant_name, variant_source_path|
20
22
  source = File.join(@temp_directory, variant_source_path)
21
23
  destination = File.join(@temp_directory, variant_name.to_s)
22
24
 
@@ -25,12 +27,11 @@ module Icons
25
27
  raise "[Icons] Failed to find the icons directory: '#{source}'" unless Dir.exist?(source)
26
28
 
27
29
  move_icons(source, destination)
28
-
29
30
  apply_transformations_to(destination)
30
31
  end
31
32
 
32
33
  remove_files_and_folders_for(original_variants)
33
- remove_previously_downloaded(excluded_variants)
34
+ remove_previously_downloaded(@library[:variants].keys - effective_variants)
34
35
 
35
36
  puts "[Icons] Icon variants processed successfully"
36
37
  end
data/lib/icons/sync.rb CHANGED
@@ -5,12 +5,13 @@ require "icons/sync/process_variants"
5
5
 
6
6
  module Icons
7
7
  class Sync
8
- def initialize(name)
8
+ def initialize(name, variants: nil)
9
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
13
- @temp_directory = File.join(temp_directory_root, name)
13
+ @variants = variants
14
+ @temp_directory = File.join(temp_directory_root, name.to_s)
14
15
  end
15
16
 
16
17
  def now
@@ -52,11 +53,14 @@ module Icons
52
53
  end
53
54
 
54
55
  def sparse_checkout_paths
55
- @library[:variants].values.map { |path| "'#{path}'" }.join(" ")
56
+ paths = @library[:variants]
57
+ paths = paths.slice(*@variants) if @variants
58
+
59
+ paths.values.map { |path| "'#{path}'" }.join(" ")
56
60
  end
57
61
 
58
62
  def process_variants
59
- Sync::ProcessVariants.new(@temp_directory, @name, @library).process
63
+ Sync::ProcessVariants.new(@temp_directory, @name, @library, variants: @variants).process
60
64
  end
61
65
 
62
66
  def remove_non_svg_files
data/lib/icons/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Icons
2
- VERSION = "0.9.0"
2
+ VERSION = "0.11.0"
3
3
  end
data/lib/icons.rb CHANGED
@@ -4,6 +4,7 @@ require "icons/version"
4
4
  require "icons/errors"
5
5
  require "icons/libraries"
6
6
  require "icons/configuration"
7
+ require "icons/configuration/custom_library"
7
8
  require "icons/icon"
8
9
  require "icons/sprite/reference"
9
10
  require "icons/sprite"
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.9.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rails Designer
@@ -52,6 +52,7 @@ files:
52
52
  - lib/icons/configuration.rb
53
53
  - lib/icons/configuration/animated.rb
54
54
  - lib/icons/configuration/boxicons.rb
55
+ - lib/icons/configuration/custom_library.rb
55
56
  - lib/icons/configuration/feather.rb
56
57
  - lib/icons/configuration/flags.rb
57
58
  - lib/icons/configuration/heroicons.rb
@@ -90,14 +91,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
91
  requirements:
91
92
  - - ">="
92
93
  - !ruby/object:Gem::Version
93
- version: '0'
94
+ version: 3.1.0
94
95
  required_rubygems_version: !ruby/object:Gem::Requirement
95
96
  requirements:
96
97
  - - ">="
97
98
  - !ruby/object:Gem::Version
98
99
  version: '0'
99
100
  requirements: []
100
- rubygems_version: 4.0.14
101
+ rubygems_version: 4.0.22
101
102
  specification_version: 4
102
103
  summary: Add any icon library to a Ruby app
103
104
  test_files: []