rails_icons 0.3.0 → 1.0.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: 6c3ee60bafe9a9cffae818c8304e8a69abf56d8de147ff607db5d775137ab5ea
4
- data.tar.gz: afacf89281c87e029a0866860ef6edf1a738e06d5918b5254524c2bbe803bbd3
3
+ metadata.gz: 50dffad405d19a7a365d8dd5684422ac4b0b31fc5e8c9e001d841c2625ed0f66
4
+ data.tar.gz: ac27f4feb6a7dae8d240896cbcad704675f566080aea2a1df4bad68608bcd0ae
5
5
  SHA512:
6
- metadata.gz: f1f4ed187c437220dc0b081dbddb95f1204f65a30dca2b89c4b72aba7574888d5adee9766a69821ecb26d2f9e9adff2e78d8b585ec7f639dd8d9754b0cb9296f
7
- data.tar.gz: e195bd6ade61e3018a478852d293c8437d0c0490c5d8727d774098c98a10189b4be7d982f73ebb191ce5486a947f46c424265f46fe79fec3fe03ae3e45be543a
6
+ metadata.gz: 1b3b458095eb630a39f217be671c6bf58dc400c6e5caea9e7eee7ceebc51df6329dced01d3451f483b936f3fb5d59aaeea05de519565e36c12de3aa80abfbeb3
7
+ data.tar.gz: 60a93aed59ef5c518c39d95b3814062a02240aa86cbfe34ca771164504747ea965fae97a3456cc50dc06e620c04ccc2c5d7825d7724ec7f3850abd583be0cf91
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_icons (0.3.0)
4
+ rails_icons (1.0.0)
5
5
  nokogiri (~> 1.16, >= 1.16.4)
6
6
  rails (> 6.1)
7
7
 
data/README.md CHANGED
@@ -1,114 +1,124 @@
1
1
  # Rails Icons
2
2
 
3
- Embed any library's icon in your Rails app. There are many icon gems for Rails already, but none are library-agnostic. This means you need to pull in other gems or add your logic to display that one specific icon.
3
+ Add any icon library to a Rails app. Rails Icons has first-party support for a [handful of libraries](#first-party-libraries). It is library agnostic so it can be used with any icon library using the same interface.
4
4
 
5
- The first-party supported icons are stored in a seperate repo: [rails_icons_vault](https://github.com/Rails-Designer/rails_icons_vault). This allows you to pull in only the icon libraries you need, keeping the rails_icons gem lean and lightweight.
5
+ ```erb
6
+ # Using the default icon library
7
+ <%= icon "check", class: "text-gray-500" %>
6
8
 
9
+ # Using any custom library
10
+ <%= icon "apple", library: "simple_icons", class: "text-black" %>
11
+ ```
12
+
13
+ The icons are sourced directly from their respective GitHub repositories, ensuring Rails Icons remain lightweight.
7
14
 
8
- ## Sponsored By [Rails Designer](https://railsdesigner.com/)
15
+
16
+ **Sponsored By [Rails Designer](https://railsdesigner.com/)**
9
17
 
10
18
  <a href="https://railsdesigner.com/" target="_blank">
11
- <img src="https://raw.githubusercontent.com/Rails-Designer/rails_icons/main/docs/rails_designer_icon.jpg" alt="Rails Designer logo" width="300" />
19
+ <img src="https://raw.githubusercontent.com/Rails-Designer/rails_icons/main/docs/rails_designer_icon.jpg" alt="Rails Designer logo" width="240" />
12
20
  </a>
13
21
 
14
22
 
15
23
  ## Install
16
24
 
17
- Add this line to your Gemfile:
18
-
19
- ```ruby
20
- gem "rails_icons"
25
+ Add the gem
26
+ ```bash
27
+ bundle add rails_icons
21
28
  ```
22
29
 
23
- And run:
24
-
30
+ Install, choosing one of the supported libraries
25
31
  ```bash
26
- bundle
32
+ rails generate rails_icons:install --libraries=LIBRARY_NAME
27
33
  ```
28
34
 
29
- Sync any of the supported icon libraries from the
30
- [rails_icons_vault](https://github.com/Rails-Designer/rails_icons_vault):
31
-
35
+ **Example**
32
36
  ```bash
33
- rails generate rails_icons:sync heroicons
37
+ rails generate rails_icons:install --libraries=heroicons
38
+
39
+ Or multiple at once
40
+ rails generate rails_icons:install --libraries=heroicons lucide
34
41
  ```
35
42
 
36
43
 
37
44
  ## Usage
38
45
 
39
46
  ```ruby
40
- # The default library is Heroicons, with "outline" as the default set
47
+ # Uses the default library and variant defined in config/initializer/rails_icons.rb
41
48
  icon "check"
42
49
 
43
- # Use another set (options are: outline, solid, mini, micro)
44
- icon "check", set: "solid"
50
+ # Use another variant
51
+ icon "check", variant: "solid"
52
+
53
+ # Set library explictly
54
+ icon "check", library: "heroicons"
45
55
 
46
- # Add CSS to the icon
56
+ # Add CSS
47
57
  icon "check", class: "text-green-500"
48
58
 
49
59
  # Add data attributes
50
60
  icon "check", data: { controller: "swap" }
51
61
 
52
- # Tweak the stroke-width
62
+ # Set the stroke-width
53
63
  icon "check", stroke_width: 2
54
64
  ```
55
65
 
56
66
 
57
- ## Initializer
67
+ ## First-party libraries
58
68
 
59
- ```ruby
60
- RailsIcons.configure do |config|
61
- # Set the default set for the library
62
- config.default_library = "heroicons"
63
- config.default_set = "outline"
69
+ - [Feather](https://github.com/feathericons/feather)
70
+ - [Heroicons](https://github.com/tailwindlabs/heroicons)
71
+ - [Lucide](https://github.com/lucide-icons/lucide)
72
+ - [Tabler](https://github.com/tabler/tabler-icons)
64
73
 
65
- config.libraries.heroicons.solid.default.css = "w-6 h-6"
66
- config.libraries.heroicons.solid.default.data = {}
67
74
 
68
- config.libraries.heroicons.outline.default.css = "w-6 h-6"
69
- config.libraries.heroicons.outline.default.stroke_width = "1.5"
70
- config.libraries.heroicons.outline.default.data = {}
75
+ ## Animated icons
71
76
 
72
- config.libraries.heroicons.mini.default.css = "w-5 h-5"
73
- config.libraries.heroicons.mini.default.data = {}
77
+ Rails Icons also includes a few animated icons. Great for loading states and so on. These are currently included:
74
78
 
75
- config.libraries.heroicons.micro.default.css = "w-4 h-4"
76
- config.libraries.heroicons.micro.default.data = {}
77
- end
78
- ```
79
+ - `faded-spinner`
80
+ - `trailing-spinner`
81
+ - `fading-dots`
82
+ - `bouncing-dots`
83
+
84
+ Use like this: `icon "faded-spinner", library: "animated"`. The same attributes as other libraries are available.
79
85
 
80
- Or run `rails generate rails_icons:initializer`.
81
86
 
87
+ ## Custom icon library
82
88
 
83
- ## Add a custom icon library
89
+ Need to use an icon from another library?
90
+
91
+ 1. run `rails generate rails_icons:initializer --custom=simple_icons`;
92
+ 2. add the (SVG) icons to the created directory **app/assets/svg/icons/simple_icons**;
93
+
94
+ Every custom icon can now be used with the same interface as first-party icon libraries.
84
95
 
85
96
  ```ruby
86
- RailsIcons.configure do |config|
87
- # …
88
- config.libraries.merge!(
89
- {
90
- custom: {
91
- simple_icons: {
92
- solid: {
93
- path: "app/assets/svg/simple_icons/solid", # optional: the default lookup path is: `app/assets/svg/#{library_name}/#{set}`
94
- default: {
95
- css: "w-6 h-6"
96
- }
97
- }
98
- }
99
- }
100
- }
101
- )
102
- # …
103
- end
97
+ icon "apple", library: "simple_icons", class: "text-black"
104
98
  ```
105
99
 
106
- You can now use any svg-icon in the `app/assets/svg/simple_icons/solid` folder as a first-party icon:
107
100
 
108
- ```ruby
109
- icon "reddit", library: "simple_icons", set: "solid"
101
+ ## Sync icons
102
+
103
+ If a library gets updated, sync the icons to your app by running
104
+
105
+ ```bash
106
+ rails generate rails_icons:sync --libraries=LIBRARY_NAME
110
107
  ```
111
108
 
109
+ **Example**
110
+ ```bash
111
+ rails generate rails_icons:sync --libraries=heroicons
112
+
113
+ # Or multiple at once:
114
+ rails generate rails_icons:sync --libraries=heroicons lucide
115
+ ```
116
+
117
+
118
+ ## Contributing
119
+
120
+ This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `be standardrb` before submitting pull requests. Run tests via `rails test`.
121
+
112
122
 
113
123
  ## License
114
124
 
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle fill="currentColor" stroke="none" cx="4" cy="12" r="2.5"><animateTransform attributeName="transform" dur="1s" type="translate" values="0 3.6 ; 0 -3.6; 0 3.6" repeatCount="indefinite" begin="0.1"></animateTransform></circle><circle fill="currentColor" stroke="none" cx="12" cy="12" r="2.5"><animateTransform attributeName="transform" dur="1s" type="translate" values="0 2.4 ; 0 -2.4; 0 2.4" repeatCount="indefinite" begin="0.2"></animateTransform></circle><circle fill="currentColor" stroke="none" cx="20" cy="12" r="2.5"><animateTransform attributeName="transform" dur="1s" type="translate" values="0 1.2 ; 0 -1.2; 0 1.2" repeatCount="indefinite" begin="0.3"></animateTransform></circle></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" ><defs><style>@keyframes spin {to{transform:rotate(360deg);}}</style></defs><g style="transform-origin:center;animation:spin 1s linear infinite"><circle style="opacity: 0.25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"/><path style="opacity: 0.75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/></g></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle fill="currentColor" stroke="none" cx="4" cy="12" r="2.5"> <animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.1"></animate></circle><circle fill="currentColor" stroke="none" cx="12" cy="12" r="2.5"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.2"></animate></circle><circle fill="currentColor" stroke="none" cx="20" cy="12" r="2.5"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.3"></animate></circle></svg>
@@ -0,0 +1 @@
1
+ <svg stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner{transform-origin:center; animation:spinner_outside 2s linear infinite}.spinner circle{stroke-linecap:round;animation:spinner_inside 1.5s ease-in-out infinite}@keyframes spinner_outside{100%{transform:rotate(360deg)}}@keyframes spinner_inside{0%{stroke-dasharray:0 150;stroke-dashoffset:0}47.5%{stroke-dasharray:42 150;stroke-dashoffset:-16}95%,100%{stroke-dasharray:42 150;stroke-dashoffset:-59}}</style><g class="spinner"><circle cx="12" cy="12" r="9.5" fill="none" stroke-width="4"></circle></g></svg>
@@ -1,9 +1,144 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsIcons
2
4
  class InitializerGenerator < Rails::Generators::Base
3
5
  source_root File.expand_path("templates", __dir__)
4
6
 
7
+ class_option :libraries, type: :array, default: [], desc: "Choose libraries (#{RailsIcons::Libraries.all.keys.join("/")})"
8
+ class_option :destination, type: :string, default: "app/assets/svg/icons/", desc: "Specify destination folder for icons"
9
+ class_option :custom, type: :string, desc: "Name of the custom library"
10
+
5
11
  def copy_initializer
6
- copy_file "initializer.rb", "config/initializers/rails_icons.rb"
12
+ return if File.exist?(INITIALIZER)
13
+
14
+ copy_file "initializer.rb", INITIALIZER
15
+ end
16
+
17
+ def insert_default_configuration
18
+ return unless File.exist?(INITIALIZER)
19
+ return if default_configuration_exists?
20
+
21
+ if options[:libraries].present?
22
+ default_configuration = <<~RB.indent(2)
23
+ config.default_library = "#{options[:libraries].first}"
24
+ # config.default_variant = "" # Set a default variant if multiple exist
25
+ RB
26
+
27
+ insert_into_file INITIALIZER, default_configuration, after: "RailsIcons.configure do |config|\n"
28
+ end
29
+ end
30
+
31
+ def insert_libraries_configuration
32
+ insert_into_file INITIALIZER, "\n#{library_configuration}", before: "end"
33
+ end
34
+
35
+ def setup_custom_configuration
36
+ return "" if options[:custom].blank?
37
+
38
+ insert_custom_configuration
39
+ create_custom_directory
40
+ end
41
+
42
+ private
43
+
44
+ INITIALIZER = "config/initializers/rails_icons.rb"
45
+
46
+ def insert_custom_configuration
47
+ unless File.read(INITIALIZER).include?("config.libraries.merge!")
48
+ custom_default_configuration = <<~RB.indent(2)
49
+ config.libraries.merge!(
50
+
51
+ {
52
+ custom: {
53
+ }
54
+ }
55
+ )
56
+ RB
57
+
58
+ insert_into_file INITIALIZER, custom_default_configuration, before: "end"
59
+ end
60
+
61
+ insert_into_file INITIALIZER, "\n#{custom_configuration}", after: "custom: {"
62
+ end
63
+
64
+ def create_custom_directory
65
+ FileUtils.mkdir_p(File.join(options[:destination], options[:custom]))
66
+ end
67
+
68
+ def library_configuration
69
+ configs = {
70
+ feather: feather_config,
71
+ heroicons: heroicons_config,
72
+ lucide: lucide_config,
73
+ tabler: tabler_config
74
+ }
75
+
76
+ options[:libraries].map { configs[_1.to_sym] }.join("\n")
77
+ end
78
+
79
+ def feather_config
80
+ <<~RB.indent(2)
81
+ # Override Feather defaults
82
+ # config.libraries.feather.default.css = "size-6"
83
+ # config.libraries.feather.default.stroke_width = "2"
84
+ # config.libraries.feather.default.data = {}
85
+ RB
86
+ end
87
+
88
+ def heroicons_config
89
+ <<~RB.indent(2)
90
+ # Override Heroicon defaults
91
+ # config.libraries.heroicons.outline.default.css = "size-6"
92
+ # config.libraries.heroicons.outline.default.stroke_width = "1.5"
93
+ # config.libraries.heroicons.outline.default.data = {}
94
+
95
+ # config.libraries.heroicons.solid.default.css = "size-6"
96
+ # config.libraries.heroicons.solid.default.data = {}
97
+
98
+ # config.libraries.heroicons.mini.default.css = "size-5"
99
+ # config.libraries.heroicons.mini.default.data = {}
100
+
101
+ # config.libraries.heroicons.micro.default.css = "size-4"
102
+ # config.libraries.heroicons.micro.default.data = {}
103
+ RB
104
+ end
105
+
106
+ def lucide_config
107
+ <<~RB.indent(2)
108
+ # Override Lucide defaults
109
+ # config.libraries.lucide.outline.default.css = "size-6"
110
+ # config.libraries.lucide.outline.default.stroke_width = "1.5"
111
+ # config.libraries.lucide.outline.default.data = {}
112
+ RB
113
+ end
114
+
115
+ def tabler_config
116
+ <<~RB.indent(2)
117
+ # Override Tabler defaults
118
+ # config.libraries.tabler.solid.default.css = "size-6"
119
+ # config.libraries.tabler.solid.default.data = {}
120
+
121
+ # config.libraries.tabler.outline.default.css = "size-6"
122
+ # config.libraries.tabler.outline.default.stroke_width = "2"
123
+ # config.libraries.tabler.outline.default.data = {}
124
+ RB
125
+ end
126
+
127
+ def custom_configuration
128
+ <<~RB.indent(8)
129
+ #{options[:custom]}: {
130
+ # path: "app/assets/svg/icons/#{options[:custom]}/",
131
+ default: {
132
+ css: "size-6"
133
+ }
134
+ }
135
+ RB
136
+ end
137
+
138
+ def default_configuration_exists?
139
+ line = /^\s*config\.default_library\s*=/
140
+
141
+ File.readlines(INITIALIZER).any? { _1.match?(line) }
7
142
  end
8
143
  end
9
144
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsIcons
4
+ class InstallGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("templates", __dir__)
6
+
7
+ class_option :libraries, type: :array, default: [], desc: "Choose libraries (#{RailsIcons::Libraries.all.keys.join("/")})"
8
+ class_option :destination, type: :string, default: "app/assets/svg/icons/", desc: "Specify destination folder for icons"
9
+ class_option :skip_sync, type: :boolean, default: false
10
+
11
+ def initializer_generator
12
+ generate("rails_icons:initializer", *attributes)
13
+ end
14
+
15
+ def sync_generator
16
+ return if options[:skip_sync] || options[:libraries].blank?
17
+
18
+ generate("rails_icons:sync", *attributes)
19
+ end
20
+
21
+ private
22
+
23
+ def attributes = ["--libraries=#{options[:libraries].join(" ")}", "--destination=#{options[:destination]}"].join(" ")
24
+ end
25
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module RailsIcons
6
+ module Sync
7
+ class Engine < Rails::Generators::Base
8
+ def initialize(temp_icons_directory, library)
9
+ super
10
+
11
+ @temp_directory, @library = File.join(temp_icons_directory, library[:name]), library
12
+ end
13
+
14
+ def sync
15
+ clone
16
+ filter_variants_from_directory
17
+ remove_non_svg_files
18
+ rescue => error
19
+ say "[Rails Icons] Failed to sync icons: #{error.message}", :red
20
+
21
+ post_error_clean_up
22
+
23
+ raise
24
+ end
25
+
26
+ private
27
+
28
+ def clone
29
+ raise "[Rails Icons] Failed to clone repository" unless system("git clone '#{@library[:url]}' '#{@temp_directory}'")
30
+
31
+ say "#{@library[:name]} repository cloned successfully."
32
+ end
33
+
34
+ def filter_variants_from_directory
35
+ original_set_list = Dir.children(@temp_directory)
36
+
37
+ @library[:variants].each do |variant_name, variant_source_path|
38
+ source = File.join(@temp_directory, variant_source_path)
39
+ destination = File.join(@temp_directory, variant_name.to_s)
40
+
41
+ # Whitelist variant directory if present in original_set_list to prevent deletion
42
+ original_set_list.delete(variant_name.to_s)
43
+
44
+ raise "[Rails Icons] Failed to find the icons directory: '#{source}'" unless Dir.exist?(source)
45
+
46
+ move_icons(source, destination)
47
+ end
48
+
49
+ remove_files_and_folders(original_set_list)
50
+
51
+ say "[Rails Icons] Icon variants filtered successfully"
52
+ end
53
+
54
+ def remove_non_svg_files
55
+ Pathname.glob("#{@temp_directory}/**/*")
56
+ .select { |p| p.file? && p.extname != ".svg" }
57
+ .each(&:delete)
58
+
59
+ say "[Rails Icons] Non-SVG files removed successfully"
60
+ end
61
+
62
+ def post_error_clean_up
63
+ if yes?("Do you want to remove the temp files? ('#{@temp_directory}')")
64
+ say "[Rails Icons] Cleaning up…"
65
+
66
+ FileUtils.rm_rf(@temp_directory)
67
+ else
68
+ say "[Rails Icons] Keeping files at: '#{@temp_directory}'"
69
+ end
70
+ end
71
+
72
+ def move_icons(source, destination)
73
+ FileUtils.mkdir_p(destination)
74
+
75
+ Dir.children(source).each do |item|
76
+ FileUtils.mv(File.join(source, item), destination)
77
+ end
78
+ end
79
+
80
+ def remove_files_and_folders(paths)
81
+ paths.each do |path|
82
+ FileUtils.rm_rf(File.join(@temp_directory, path))
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -1,51 +1,59 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fileutils"
4
+ require_relative "sync/engine"
2
5
 
3
6
  module RailsIcons
4
7
  class SyncGenerator < Rails::Generators::Base
5
- ICON_VAULT_REPO_URL = "https://github.com/Rails-Designer/rails_icons_vault.git".freeze
6
-
7
- argument :libraries, type: :array, default: [], banner: "heroicons lucide"
8
-
9
- class_option :destination, type: :string, default: nil, desc: "Custom destination folder for icons (default: `app/assets/svg/icons/`)"
8
+ class_option :libraries, type: :array, default: [], desc: "Choose libraries (#{RailsIcons::Libraries.all.keys.join("/")})"
9
+ class_option :destination, type: :string, default: "app/assets/svg/icons/", desc: "Specify destination folder for icons"
10
10
 
11
- desc "Sync a specified icon set(s) from the Rails Icons Vault (https://github.com/Rails-Designer/rails_icons_vault)"
11
+ desc "Sync an icon library(s) from their respective git repos."
12
12
  source_root File.expand_path("templates", __dir__)
13
13
 
14
14
  def sync_icons
15
- icons_dir = options[:destination] || Rails.root.join("app/assets/svg/icons")
16
- tmp_dir = Rails.root.join("tmp/icons")
15
+ raise "[Rails Icons] Not a valid library" if options[:libraries].empty?
16
+
17
+ clean_temp_directory
18
+
19
+ options[:libraries].each { |library| sync(library) }
20
+
21
+ clean_temp_directory
22
+ end
23
+
24
+ private
17
25
 
18
- FileUtils.rm_rf(tmp_dir) if Dir.exist?(tmp_dir)
19
- FileUtils.mkdir_p(tmp_dir)
26
+ def clean_temp_directory
27
+ FileUtils.rm_rf(temp_directory) if Dir.exist?(temp_directory)
28
+ end
20
29
 
21
- if system("git clone '#{ICON_VAULT_REPO_URL}' '#{tmp_dir}'")
22
- say "Repository cloned successfully.", :green
23
- else
24
- say "Failed to clone repository.", :red
30
+ def sync(name)
31
+ library = RailsIcons::Libraries.all.fetch(name.to_sym)
32
+ library_path = File.join(temp_directory, library[:name])
25
33
 
26
- exit 1
27
- end
34
+ Sync::Engine.new(temp_directory, library).sync
28
35
 
29
- libraries.each do |set|
30
- set_path = File.join(tmp_dir, "icons", set)
36
+ raise_library_not_found(name) unless Dir.exist?(library_path)
37
+ copy_library(library[:name], library_path)
38
+ end
31
39
 
32
- if Dir.exist?(set_path)
33
- destination_path = File.join(icons_dir, set)
40
+ def temp_directory
41
+ Rails.root.join("tmp/icons")
42
+ end
34
43
 
35
- FileUtils.mkdir_p(destination_path)
36
- FileUtils.cp_r(Dir.glob("#{set_path}/*"), destination_path)
44
+ def copy_library(library, source)
45
+ destination = File.join(options[:destination], library)
37
46
 
38
- say "Synced `#{set}` icons for set", :green
39
- else
40
- say "Icon set `#{set}` not found", :red
47
+ FileUtils.mkdir_p(destination)
41
48
 
42
- exit 1
43
- end
44
- end
49
+ FileUtils.cp_r(Dir.glob("#{source}/*"), destination)
45
50
 
46
- FileUtils.rm_rf(tmp_dir)
51
+ say "[Rails Icons] Synced '#{library}' library successfully #{%w[😃 🎉 ✨].sample}", :green
52
+ end
47
53
 
48
- say "Icons synced successfully", :green
54
+ def raise_library_not_found(library)
55
+ say "[Rails Icons] Could not find '#{library}' library 🤷", :red
56
+ exit 1
49
57
  end
50
58
  end
51
59
  end
@@ -1,18 +1,2 @@
1
1
  RailsIcons.configure do |config|
2
- # Set the default set for the library
3
- config.default_library = "heroicons" # https://heroicons.com/
4
- config.default_set = "outline" # other sets for Heroicons are: solid, mini, micro
5
-
6
- config.libraries.heroicons.solid.default.css = "w-6 h-6"
7
- config.libraries.heroicons.solid.default.data = {}
8
-
9
- config.libraries.heroicons.outline.default.css = "w-6 h-6"
10
- config.libraries.heroicons.outline.default.stroke_width = "1.5"
11
- config.libraries.heroicons.outline.default.data = {}
12
-
13
- config.libraries.heroicons.mini.default.css = "w-5 h-5"
14
- config.libraries.heroicons.mini.default.data = {}
15
-
16
- config.libraries.heroicons.micro.default.css = "w-4 h-4"
17
- config.libraries.heroicons.micro.default.data = {}
18
2
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsIcons
4
+ class Configuration
5
+ class Animated
6
+ def config
7
+ ActiveSupport::OrderedOptions.new.tap do |options|
8
+ options.default = default_options
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def default_options
15
+ ActiveSupport::OrderedOptions.new.tap do |options|
16
+ options.css = "size-6"
17
+ options.data = {}
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsIcons
4
+ class Configuration
5
+ class Feather
6
+ def config
7
+ ActiveSupport::OrderedOptions.new.tap do |options|
8
+ options.default_variant = nil
9
+
10
+ options.default = default_options
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def default_options
17
+ ActiveSupport::OrderedOptions.new.tap do |options|
18
+ options.stroke_width = "2"
19
+ options.css = "size-6"
20
+ options.data = {}
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsIcons
4
+ class Configuration
5
+ class Heroicons
6
+ def config
7
+ ActiveSupport::OrderedOptions.new.tap do |options|
8
+ options.default_variant = :outline
9
+
10
+ setup_outline_config(options)
11
+ setup_solid_config(options)
12
+ setup_mini_config(options)
13
+ setup_micro_config(options)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def setup_outline_config(options)
20
+ options.outline = ActiveSupport::OrderedOptions.new
21
+ options.outline.default = default_outline_options
22
+ end
23
+
24
+ def setup_solid_config(options)
25
+ options.solid = ActiveSupport::OrderedOptions.new
26
+ options.solid.default = default_solid_options
27
+ end
28
+
29
+ def setup_mini_config(options)
30
+ options.mini = ActiveSupport::OrderedOptions.new
31
+ options.mini.default = default_mini_options
32
+ end
33
+
34
+ def setup_micro_config(options)
35
+ options.micro = ActiveSupport::OrderedOptions.new
36
+ options.micro.default = default_micro_options
37
+ end
38
+
39
+ def default_solid_options
40
+ ActiveSupport::OrderedOptions.new.tap do |options|
41
+ options.css = "size-6"
42
+ options.data = {}
43
+ end
44
+ end
45
+
46
+ def default_outline_options
47
+ ActiveSupport::OrderedOptions.new.tap do |options|
48
+ options.stroke_width = 1.5
49
+ options.css = "size-6"
50
+ options.data = {}
51
+ end
52
+ end
53
+
54
+ def default_mini_options
55
+ ActiveSupport::OrderedOptions.new.tap do |options|
56
+ options.css = "size-5"
57
+ options.data = {}
58
+ end
59
+ end
60
+
61
+ def default_micro_options
62
+ ActiveSupport::OrderedOptions.new.tap do |options|
63
+ options.css = "size-4"
64
+ options.data = {}
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsIcons
4
+ class Configuration
5
+ class Lucide
6
+ def config
7
+ ActiveSupport::OrderedOptions.new.tap do |options|
8
+ options.default_variant = :outline
9
+
10
+ setup_outline_config(options)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def setup_outline_config(options)
17
+ options.outline = ActiveSupport::OrderedOptions.new
18
+ options.outline.default = default_outline_options
19
+ end
20
+
21
+ def default_outline_options
22
+ ActiveSupport::OrderedOptions.new.tap do |options|
23
+ options.stroke_width = "1.5"
24
+ options.css = "size-6"
25
+ options.data = {}
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsIcons
4
+ class Configuration
5
+ class Tabler
6
+ def config
7
+ ActiveSupport::OrderedOptions.new.tap do |options|
8
+ options.default_variant = :outline
9
+
10
+ setup_outline_config(options)
11
+ setup_filled_config(options)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def setup_outline_config(options)
18
+ options.outline = ActiveSupport::OrderedOptions.new
19
+ options.outline.default = default_outline_options
20
+ end
21
+
22
+ def setup_filled_config(options)
23
+ options.filled = ActiveSupport::OrderedOptions.new
24
+ options.filled.default = default_filled_options
25
+ end
26
+
27
+ def default_outline_options
28
+ ActiveSupport::OrderedOptions.new.tap do |options|
29
+ options.stroke_width = 2
30
+ options.css = "size-6"
31
+ options.data = {}
32
+ end
33
+ end
34
+
35
+ def default_filled_options
36
+ ActiveSupport::OrderedOptions.new.tap do |options|
37
+ options.css = "size-6"
38
+ options.data = {}
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,6 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "configuration/animated"
4
+ require_relative "configuration/feather"
5
+ require_relative "configuration/heroicons"
6
+ require_relative "configuration/lucide"
7
+ require_relative "configuration/tabler"
8
+
3
9
  module RailsIcons
10
+ def self.configuration
11
+ @configuration ||= Configuration.new
12
+ end
13
+
14
+ def self.configure
15
+ yield(configuration)
16
+ end
17
+
4
18
  class Configuration
5
19
  def initialize
6
20
  @config = ActiveSupport::OrderedOptions.new
@@ -24,51 +38,17 @@ module RailsIcons
24
38
  private
25
39
 
26
40
  def set_default_config
27
- @config.helper_name = "icon"
28
- @config.default_library = "heroicons"
29
- @config.default_set = "outline"
41
+ @config.default_library = nil
30
42
  end
31
43
 
32
44
  def set_libraries_config
33
45
  @config.libraries = ActiveSupport::OrderedOptions.new
34
46
 
35
- heroicons_config
36
- lucide_config
37
- end
38
-
39
- def heroicons_config
40
- @config.libraries.heroicons = ActiveSupport::OrderedOptions.new
41
-
42
- @config.libraries.heroicons.solid = ActiveSupport::OrderedOptions.new
43
- @config.libraries.heroicons.solid.default = ActiveSupport::OrderedOptions.new
44
- @config.libraries.heroicons.solid.default.css = "w-6 h-6"
45
- @config.libraries.heroicons.solid.default.data = {}
46
-
47
- @config.libraries.heroicons.outline = ActiveSupport::OrderedOptions.new
48
- @config.libraries.heroicons.outline.default = ActiveSupport::OrderedOptions.new
49
- @config.libraries.heroicons.outline.default.stroke_width = 1.5
50
- @config.libraries.heroicons.outline.default.css = "w-6 h-6"
51
- @config.libraries.heroicons.outline.default.data = {}
52
-
53
- @config.libraries.heroicons.mini = ActiveSupport::OrderedOptions.new
54
- @config.libraries.heroicons.mini.default = ActiveSupport::OrderedOptions.new
55
- @config.libraries.heroicons.mini.default.css = "w-5 h-5"
56
- @config.libraries.heroicons.mini.default.data = {}
57
-
58
- @config.libraries.heroicons.micro = ActiveSupport::OrderedOptions.new
59
- @config.libraries.heroicons.micro.default = ActiveSupport::OrderedOptions.new
60
- @config.libraries.heroicons.micro.default.css = "w-4 h-4"
61
- @config.libraries.heroicons.micro.default.data = {}
62
- end
63
-
64
- def lucide_config
65
- @config.libraries.lucide = ActiveSupport::OrderedOptions.new
66
-
67
- @config.libraries.lucide.outline = ActiveSupport::OrderedOptions.new
68
- @config.libraries.lucide.outline.default = ActiveSupport::OrderedOptions.new
69
- @config.libraries.lucide.outline.default.stroke_width = 2
70
- @config.libraries.lucide.outline.default.css = "w-6 h-6"
71
- @config.libraries.lucide.outline.default.data = {}
47
+ @config.libraries.animated = Configuration::Animated.new.config
48
+ @config.libraries.feather = Configuration::Feather.new.config
49
+ @config.libraries.heroicons = Configuration::Heroicons.new.config
50
+ @config.libraries.lucide = Configuration::Lucide.new.config
51
+ @config.libraries.tabler = Configuration::Tabler.new.config
72
52
  end
73
53
  end
74
54
  end
@@ -5,12 +5,12 @@ require_relative "../configuration"
5
5
  module RailsIcons
6
6
  module Helpers
7
7
  module IconHelper
8
- def icon(name, library: RailsIcons.configuration.default_library, set: nil, **args)
8
+ def icon(name, library: RailsIcons.configuration.default_library, variant: nil, **arguments)
9
9
  RailsIcons::Icon.new(
10
10
  name: name,
11
11
  library: library,
12
- set: set,
13
- args: args
12
+ variant: variant,
13
+ arguments: arguments
14
14
  ).svg
15
15
  end
16
16
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsIcons
2
4
  class Icon
3
5
  class Attributes
4
- def initialize(default_attributes: {}, args: {})
5
- @merged_attributes = default_attributes.merge(args)
6
+ def initialize(default_attributes: {}, arguments: {})
7
+ @merged_attributes = default_attributes.merge(arguments)
6
8
  end
7
9
 
8
10
  def attach(to:)
@@ -1,82 +1,88 @@
1
1
  require "rails_icons/icon/attributes"
2
2
 
3
3
  class RailsIcons::Icon
4
- def initialize(name:, library:, set:, args:)
4
+ def initialize(name:, library:, arguments:, variant: nil)
5
5
  @name = name
6
- @library = library.to_s
7
- @set = set
8
- @args = args
6
+ @library = library.to_s.inquiry
7
+ @variant = (variant || set_variant).to_s
8
+ @arguments = arguments
9
9
  end
10
10
 
11
11
  def svg
12
12
  raise RailsIcons::NotFound, error_message unless File.exist?(file_path)
13
13
 
14
- svg_file = Nokogiri::HTML::DocumentFragment.parse(File.read(file_path)).at_css("svg")
15
-
16
- attach_attributes to: svg_file
17
-
18
- svg_file.to_html.html_safe
14
+ Nokogiri::HTML::DocumentFragment.parse(File.read(file_path))
15
+ .at_css("svg")
16
+ .tap { |svg| attach_attributes(to: svg) }
17
+ .to_html
18
+ .html_safe
19
19
  end
20
20
 
21
21
  private
22
22
 
23
- def error_message
24
- "Icon not found: `#{@library} / #{set} / #{@name}`"
23
+ def set_variant
24
+ RailsIcons.configuration.default_variant.presence ||
25
+ RailsIcons.configuration.libraries.dig(@library.to_sym, :default_variant)
25
26
  end
26
27
 
27
- def file_path
28
- custom_library.dig("path") ||
29
- Rails.root.join("app", "assets", "svg", "icons", @library, set, "#{@name}.svg")
28
+ def error_message
29
+ attributes = [
30
+ @library,
31
+ @variant,
32
+ @name
33
+ ].compact_blank
34
+
35
+ "Icon not found: `#{attributes.join(" / ")}`"
30
36
  end
31
37
 
32
- def custom_library?
33
- custom_library.present?
38
+ def file_path
39
+ return RailsIcons::Engine.root.join("app", "assets", "svg", "rails_icons", "icons", "animated", "#{@name}.svg") if @library.animated?
40
+ return Rails.root.join(custom_library.dig(:path), "#{@name}.svg") if custom_library?
41
+
42
+ parts = [
43
+ "app",
44
+ "assets",
45
+ "svg",
46
+ "icons",
47
+ @library,
48
+ @variant,
49
+ "#{@name}.svg"
50
+ ].compact_blank!
51
+
52
+ Rails.root.join(*parts)
34
53
  end
35
54
 
36
55
  def attach_attributes(to:)
37
56
  RailsIcons::Icon::Attributes
38
- .new(default_attributes: default_attributes, args: @args)
57
+ .new(default_attributes: default_attributes, arguments: @arguments)
39
58
  .attach(to: to)
40
59
  end
41
60
 
42
61
  def default_attributes
43
62
  {
44
- "stroke-width": default_stroke_width,
45
- class: default_css,
46
- data: default_data
63
+ "stroke-width": default(:stroke_width),
64
+ data: default(:data),
65
+ class: default(:css)
47
66
  }
48
67
  end
49
68
 
50
- def set
51
- return @set if @set.present?
52
-
53
- RailsIcons.configuration.default_set
54
- end
69
+ def default(key) = library_attributes.dig(:default, key)
55
70
 
56
- def default_css
57
- library_set_attributes.dig(:default, :css)
58
- end
59
-
60
- def default_data
61
- library_set_attributes.dig(:default, :data)
62
- end
63
-
64
- def default_stroke_width
65
- library_set_attributes.dig(:default, :stroke_width)
66
- end
67
-
68
- def library_set_attributes
69
- return custom_library || {} if custom_library?
70
-
71
- RailsIcons.configuration.libraries.dig(@library, set) || {}
71
+ def library_attributes
72
+ custom_library? ? custom_library : RailsIcons.configuration.libraries.dig(@library, @variant) || {}
72
73
  end
73
74
 
74
75
  def custom_library
75
76
  RailsIcons
76
77
  .configuration
77
78
  .libraries
78
- .dig("custom")
79
- &.with_indifferent_access
80
- &.dig(@library, set) || {}
79
+ &.dig("custom")
80
+ &.dig(@library.to_sym)&.with_defaults(
81
+ {
82
+ path: "app/assets/svg/icons/#{@library}"
83
+ }
84
+ ) || {}
81
85
  end
86
+
87
+ def custom_library? = custom_library.present?
82
88
  end
@@ -0,0 +1,45 @@
1
+ module RailsIcons
2
+ module Libraries
3
+ module_function
4
+
5
+ def all
6
+ {
7
+ feather: {
8
+ name: "feather",
9
+ url: "https://github.com/feathericons/feather.git",
10
+ variants: {
11
+ ".": "icons" # Feather has no variants, store in the top directory
12
+ }
13
+ },
14
+
15
+ heroicons: {
16
+ name: "heroicons",
17
+ url: "https://github.com/tailwindlabs/heroicons.git",
18
+ variants: {
19
+ outline: "optimized/24/outline",
20
+ solid: "optimized/24/solid",
21
+ mini: "optimized/20/solid",
22
+ micro: "optimized/16/solid"
23
+ }
24
+ },
25
+
26
+ lucide: {
27
+ name: "lucide",
28
+ url: "https://github.com/lucide-icons/lucide.git",
29
+ variants: {
30
+ outline: "icons"
31
+ }
32
+ },
33
+
34
+ tabler: {
35
+ name: "tabler",
36
+ url: "https://github.com/tabler/tabler-icons.git",
37
+ variants: {
38
+ filled: "icons/filled",
39
+ outline: "icons/outline"
40
+ }
41
+ }
42
+ }
43
+ end
44
+ end
45
+ end
@@ -9,5 +9,11 @@ module RailsIcons
9
9
  include RailsIcons::Helpers::IconHelper
10
10
  end
11
11
  end
12
+
13
+ initializer "rails_icons.assets" do |app|
14
+ gem_root = Pathname.new(Gem.loaded_specs["rails_icons"].gem_dir)
15
+
16
+ app.config.assets.paths << gem_root.join("app", "assets", "svg")
17
+ end
12
18
  end
13
19
  end
@@ -1,3 +1,3 @@
1
1
  module RailsIcons
2
- VERSION = "0.3.0"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/rails_icons.rb CHANGED
@@ -1,22 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "rails_icons/version"
4
- require_relative "rails_icons/engine"
5
4
  require_relative "rails_icons/configuration"
5
+ require_relative "rails_icons/engine"
6
6
  require_relative "rails_icons/errors"
7
7
  require_relative "rails_icons/railtie"
8
+ require_relative "rails_icons/libraries"
8
9
  require_relative "rails_icons/icon"
9
10
 
10
11
  module RailsIcons
11
- def self.configuration
12
- @configuration ||= Configuration.new
13
- end
14
-
15
- def self.configure
16
- yield(configuration)
17
- end
18
-
19
- def self.icons_directory
20
- File.join("lib", "assets", "rails_icons")
21
- end
22
12
  end
data/rails_icons.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Rails Designer Developers"]
9
9
  spec.email = ["devs@railsdesigner.com"]
10
10
 
11
- spec.summary = "Add icons from multiple icons in your Rails app"
12
- spec.description = "Add SVG icons from multiple libraries, or your own custom icon set with this one gem."
11
+ spec.summary = "Add any icon library to a Rails app"
12
+ spec.description = "Add any icon library to a Rails app, from Heroicons, to Lucide to Tabler (and others). Rails Icons is library-agnostic, so you can add any library while using the same interface."
13
13
  spec.homepage = "https://railsdesigner.com/rails-icons/"
14
14
  spec.license = "MIT"
15
15
 
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.files = Dir["{bin,app,config,db,lib,public}/**/*", "Rakefile", "README.md", "rails_icons.gemspec", "Gemfile", "Gemfile.lock"]
20
20
 
21
- spec.required_ruby_version = ">= 3.0.0"
21
+ spec.required_ruby_version = ">= 3.1.0"
22
22
  spec.add_dependency "rails", "> 6.1"
23
23
  spec.add_runtime_dependency "nokogiri", "~> 1.16", ">= 1.16.4"
24
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_icons
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rails Designer Developers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-10 00:00:00.000000000 Z
11
+ date: 2024-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -44,8 +44,9 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: 1.16.4
47
- description: Add SVG icons from multiple libraries, or your own custom icon set with
48
- this one gem.
47
+ description: Add any icon library to a Rails app, from Heroicons, to Lucide to Tabler
48
+ (and others). Rails Icons is library-agnostic, so you can add any library while
49
+ using the same interface.
49
50
  email:
50
51
  - devs@railsdesigner.com
51
52
  executables: []
@@ -56,20 +57,32 @@ files:
56
57
  - Gemfile.lock
57
58
  - README.md
58
59
  - Rakefile
60
+ - app/assets/svg/rails_icons/icons/animated/bouncing-dots.svg
61
+ - app/assets/svg/rails_icons/icons/animated/faded-spinner.svg
62
+ - app/assets/svg/rails_icons/icons/animated/fading-dots.svg
63
+ - app/assets/svg/rails_icons/icons/animated/trailing-spinner.svg
59
64
  - bin/console
60
65
  - bin/rails
61
66
  - bin/release
62
67
  - bin/setup
63
68
  - lib/generators/rails_icons/initializer_generator.rb
69
+ - lib/generators/rails_icons/install_generator.rb
70
+ - lib/generators/rails_icons/sync/engine.rb
64
71
  - lib/generators/rails_icons/sync_generator.rb
65
72
  - lib/generators/rails_icons/templates/initializer.rb.tt
66
73
  - lib/rails_icons.rb
67
74
  - lib/rails_icons/configuration.rb
75
+ - lib/rails_icons/configuration/animated.rb
76
+ - lib/rails_icons/configuration/feather.rb
77
+ - lib/rails_icons/configuration/heroicons.rb
78
+ - lib/rails_icons/configuration/lucide.rb
79
+ - lib/rails_icons/configuration/tabler.rb
68
80
  - lib/rails_icons/engine.rb
69
81
  - lib/rails_icons/errors.rb
70
82
  - lib/rails_icons/helpers/icon_helper.rb
71
83
  - lib/rails_icons/icon.rb
72
84
  - lib/rails_icons/icon/attributes.rb
85
+ - lib/rails_icons/libraries.rb
73
86
  - lib/rails_icons/railtie.rb
74
87
  - lib/rails_icons/version.rb
75
88
  - rails_icons.gemspec
@@ -87,15 +100,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
100
  requirements:
88
101
  - - ">="
89
102
  - !ruby/object:Gem::Version
90
- version: 3.0.0
103
+ version: 3.1.0
91
104
  required_rubygems_version: !ruby/object:Gem::Requirement
92
105
  requirements:
93
106
  - - ">="
94
107
  - !ruby/object:Gem::Version
95
108
  version: '0'
96
109
  requirements: []
97
- rubygems_version: 3.5.15
110
+ rubygems_version: 3.5.23
98
111
  signing_key:
99
112
  specification_version: 4
100
- summary: Add icons from multiple icons in your Rails app
113
+ summary: Add any icon library to a Rails app
101
114
  test_files: []