kiso-icons 0.1.0.pre
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 +7 -0
- data/CHANGELOG.md +26 -0
- data/MIT-LICENSE +20 -0
- data/README.md +134 -0
- data/Rakefile +19 -0
- data/data/lucide.json.gz +0 -0
- data/lib/install/bin/kiso-icons +6 -0
- data/lib/install/install.rb +7 -0
- data/lib/kiso/icons/api_client.rb +79 -0
- data/lib/kiso/icons/cache.rb +28 -0
- data/lib/kiso/icons/commands.rb +149 -0
- data/lib/kiso/icons/configuration.rb +15 -0
- data/lib/kiso/icons/helper.rb +39 -0
- data/lib/kiso/icons/railtie.rb +25 -0
- data/lib/kiso/icons/renderer.rb +60 -0
- data/lib/kiso/icons/resolver.rb +78 -0
- data/lib/kiso/icons/set.rb +148 -0
- data/lib/kiso/icons/version.rb +7 -0
- data/lib/kiso/icons.rb +46 -0
- data/lib/kiso-icons.rb +3 -0
- data/lib/tasks/kiso_icons_tasks.rake +9 -0
- metadata +109 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6f91c4c7b067ad325b199468604b89aead98ba16f3c99469aff5e2ef836d4878
|
|
4
|
+
data.tar.gz: d9f4b770b5081f8bbd463591710dadb8b9e198b4526bb226d60563f065b92c1e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2db2872c247bc11a982224eff8feb89ddc63b2ba51b96aba1783e5c9fab9dadf73b336554fb0caa13b26014028e64d0be5ad5db0656382c472650a179ba1fdd2
|
|
7
|
+
data.tar.gz: 9633012b948ac6fb942ef2b51408dc4c1cd64f82daf61d4c3cadb4d1957bd43d377afab5cdc9f376ba38f8a307bf39608ef3d97d13bb7c4dba7e9cd0642b4194
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0.pre] - 2026-02-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Inline SVG rendering via `kiso_icon_tag` helper
|
|
15
|
+
- CLI (`bin/kiso-icons`) for pinning, unpinning, and listing icon sets
|
|
16
|
+
- Support for all 224 Iconify icon sets (299k+ icons)
|
|
17
|
+
- Vendored Lucide icon set as zero-config default (81KB gzipped)
|
|
18
|
+
- Resolution cascade: vendored JSON → bundled Lucide → Iconify API fallback
|
|
19
|
+
- Thread-safe in-memory icon cache
|
|
20
|
+
- Alias resolution with rotation/flip transforms (up to 5 levels)
|
|
21
|
+
- Iconify API fallback in development with prompt to pin
|
|
22
|
+
- Rails generator (`kiso_icons:install`) for project setup
|
|
23
|
+
- `pristine` command to re-download all pinned sets
|
|
24
|
+
|
|
25
|
+
[Unreleased]: https://github.com/steveclarke/kiso-icons/compare/v0.1.0.pre...HEAD
|
|
26
|
+
[0.1.0.pre]: https://github.com/steveclarke/kiso-icons/releases/tag/v0.1.0.pre
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) Stephen Clarke
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Kiso Icons 基礎
|
|
2
|
+
|
|
3
|
+
Iconify icons for Rails. Use any of [224 icon sets](https://icon-sets.iconify.design/) (299k+ icons) as inline SVG. No JavaScript needed.
|
|
4
|
+
|
|
5
|
+
Icons live in `vendor/icons/` as JSON files. Commit them to git, just like vendored JavaScript with importmap-rails.
|
|
6
|
+
|
|
7
|
+
Part of the [Kiso 基礎](https://github.com/steveclarke/kiso) family. Works on its own in any Rails 8+ app.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
./bin/bundle add kiso-icons
|
|
13
|
+
./bin/rails kiso_icons:install
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This creates `vendor/icons/` and a `bin/kiso-icons` binstub.
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
[Lucide](https://lucide.dev) ships with the gem. Use it right away:
|
|
21
|
+
|
|
22
|
+
```erb
|
|
23
|
+
<%= kiso_icon_tag("check") %>
|
|
24
|
+
<%= kiso_icon_tag("arrow-right") %>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Want a different icon set? Pin it:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
./bin/kiso-icons pin heroicons
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then use it with the set name as a prefix:
|
|
34
|
+
|
|
35
|
+
```erb
|
|
36
|
+
<%= kiso_icon_tag("heroicons:home") %>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Browse all sets at [icon-sets.iconify.design](https://icon-sets.iconify.design/).
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```erb
|
|
44
|
+
<%= kiso_icon_tag("lucide:check") %>
|
|
45
|
+
<%= kiso_icon_tag("check") %> <%# uses the default set (lucide) %>
|
|
46
|
+
<%= kiso_icon_tag("check", class: "w-5 h-5") %> <%# add CSS classes %>
|
|
47
|
+
<%= kiso_icon_tag("check", aria: { label: "Done" }) %> <%# screen reader label %>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
You can pass any HTML attribute. If you add `aria: { label: "..." }`, screen readers will see the icon and `aria-hidden` is removed.
|
|
51
|
+
|
|
52
|
+
### Pin icon sets
|
|
53
|
+
|
|
54
|
+
The `pin` command downloads an Iconify JSON file to `vendor/icons/`. Commit it to git. In production, icons load from these files with no API calls.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
./bin/kiso-icons pin lucide # pin Lucide (replaces the bundled copy)
|
|
58
|
+
./bin/kiso-icons pin heroicons mdi # pin more than one set at once
|
|
59
|
+
./bin/kiso-icons unpin heroicons # remove a set
|
|
60
|
+
./bin/kiso-icons pristine # re-download all pinned sets
|
|
61
|
+
./bin/kiso-icons list # show what's pinned
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
Add an initializer to change the defaults:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
# config/initializers/kiso_icons.rb
|
|
70
|
+
Kiso::Icons.configure do |config|
|
|
71
|
+
config.default_set = "lucide" # icon set used when no prefix is given
|
|
72
|
+
config.vendor_path = "vendor/icons" # where pinned JSON files are stored
|
|
73
|
+
config.fallback_to_api = false # fetch missing icons from the Iconify API
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
| Option | Default | What it does |
|
|
78
|
+
|--------|---------|-------------|
|
|
79
|
+
| `default_set` | `"lucide"` | Icon set used when you write `kiso_icon_tag("check")` with no prefix. |
|
|
80
|
+
| `vendor_path` | `"vendor/icons"` | Where pinned JSON files are stored. |
|
|
81
|
+
| `fallback_to_api` | `true` in dev, `false` in prod | If `true`, missing icons are fetched from the Iconify API. A log message tells you to pin the set. |
|
|
82
|
+
|
|
83
|
+
> [!TIP]
|
|
84
|
+
> In production, `fallback_to_api` is off. Pin all the sets you need so icons load from local files.
|
|
85
|
+
|
|
86
|
+
## How it works
|
|
87
|
+
|
|
88
|
+
Icons are found in this order:
|
|
89
|
+
|
|
90
|
+
1. **Pinned JSON** — your sets in `vendor/icons/`
|
|
91
|
+
2. **Bundled Lucide** — ships with the gem (81 KB gzipped), works with no setup
|
|
92
|
+
3. **Iconify API** — only in dev mode, with a prompt to pin
|
|
93
|
+
|
|
94
|
+
Each SVG uses `width="1em"`, `height="1em"`, and `currentColor`. It inherits its size from `font-size` and its color from the parent element. No CSS framework needed.
|
|
95
|
+
|
|
96
|
+
## Development
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
git clone https://github.com/steveclarke/kiso-icons.git
|
|
100
|
+
cd kiso-icons
|
|
101
|
+
bin/setup # install deps + pin demo icon sets
|
|
102
|
+
bin/dev # start demo app at http://localhost:3100
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`bin/dev` starts a Rails app that shows icons from 10 sets. You can change the port: `bin/dev 4200`.
|
|
106
|
+
|
|
107
|
+
Run tests:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
bundle exec rake test # unit tests (no Rails)
|
|
111
|
+
bundle exec rake test_integration # integration tests (boots Rails)
|
|
112
|
+
bundle exec rake # both
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) to help out.
|
|
116
|
+
|
|
117
|
+
## Project layout
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
bin/ dev scripts and CLI binstub
|
|
121
|
+
data/ bundled Lucide icon set (gzipped JSON)
|
|
122
|
+
lib/ gem source code
|
|
123
|
+
test/ unit and integration tests
|
|
124
|
+
test/dummy/ Rails app used for integration tests and the demo
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Requirements
|
|
128
|
+
|
|
129
|
+
- Ruby >= 3.2
|
|
130
|
+
- Rails >= 8.0
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT License. See [MIT-LICENSE](MIT-LICENSE).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/testtask"
|
|
5
|
+
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
|
7
|
+
t.libs << "test"
|
|
8
|
+
t.libs << "lib"
|
|
9
|
+
t.test_files = FileList["test/*_test.rb"]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Rake::TestTask.new(:test_integration) do |t|
|
|
13
|
+
t.libs << "test"
|
|
14
|
+
t.libs << "lib"
|
|
15
|
+
t.test_files = FileList["test/integration/**/*_test.rb"]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
task test_all: [:test, :test_integration]
|
|
19
|
+
task default: :test_all
|
data/data/lucide.json.gz
ADDED
|
Binary file
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Kiso
|
|
8
|
+
module Icons
|
|
9
|
+
class ApiClient
|
|
10
|
+
API_BASE = "https://api.iconify.design"
|
|
11
|
+
TIMEOUT = 5
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def fetch_icon(set_prefix, icon_name)
|
|
15
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
16
|
+
|
|
17
|
+
uri = URI("#{API_BASE}/#{set_prefix}/#{icon_name}.json")
|
|
18
|
+
response = make_request(uri)
|
|
19
|
+
return nil unless response
|
|
20
|
+
|
|
21
|
+
data = JSON.parse(response.body)
|
|
22
|
+
return nil unless data["body"]
|
|
23
|
+
|
|
24
|
+
elapsed_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) * 1000).round
|
|
25
|
+
|
|
26
|
+
warn_to_pin(set_prefix, icon_name, elapsed_ms)
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
body: data["body"],
|
|
30
|
+
width: data["width"] || 24,
|
|
31
|
+
height: data["height"] || 24
|
|
32
|
+
}
|
|
33
|
+
rescue JSON::ParserError => e
|
|
34
|
+
warn "[Kiso::Icons] Failed to parse API response for #{set_prefix}:#{icon_name}: #{e.message}"
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def make_request(uri)
|
|
41
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
42
|
+
http.use_ssl = true
|
|
43
|
+
http.open_timeout = TIMEOUT
|
|
44
|
+
http.read_timeout = TIMEOUT
|
|
45
|
+
|
|
46
|
+
request = Net::HTTP::Get.new(uri)
|
|
47
|
+
request["Accept"] = "application/json"
|
|
48
|
+
|
|
49
|
+
response = http.request(request)
|
|
50
|
+
|
|
51
|
+
case response
|
|
52
|
+
when Net::HTTPSuccess then response
|
|
53
|
+
when Net::HTTPNotFound then nil
|
|
54
|
+
else
|
|
55
|
+
warn "[Kiso::Icons] API returned #{response.code} for #{uri}"
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
rescue Net::OpenTimeout, Net::ReadTimeout
|
|
59
|
+
warn "[Kiso::Icons] API timeout for #{uri} (#{TIMEOUT}s)"
|
|
60
|
+
nil
|
|
61
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
|
62
|
+
warn "[Kiso::Icons] Network error: #{e.message}"
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def warn_to_pin(set_prefix, icon_name, elapsed_ms)
|
|
67
|
+
message = "[Kiso::Icons] Fetched #{set_prefix}:#{icon_name} from Iconify API (#{elapsed_ms}ms).\n" \
|
|
68
|
+
" Pin this set for offline use: bin/kiso-icons pin #{set_prefix}"
|
|
69
|
+
|
|
70
|
+
if defined?(Rails) && defined?(Rails.logger)
|
|
71
|
+
Rails.logger.debug { message }
|
|
72
|
+
else
|
|
73
|
+
warn message
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Icons
|
|
5
|
+
class Cache
|
|
6
|
+
def initialize
|
|
7
|
+
@store = {}
|
|
8
|
+
@mutex = Mutex.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def get(set_prefix, name)
|
|
12
|
+
@mutex.synchronize { @store["#{set_prefix}:#{name}"] }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def set(set_prefix, name, data)
|
|
16
|
+
@mutex.synchronize { @store["#{set_prefix}:#{name}"] = data.freeze }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def clear!
|
|
20
|
+
@mutex.synchronize { @store.clear }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def size
|
|
24
|
+
@mutex.synchronize { @store.size }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thor"
|
|
4
|
+
require "kiso/icons"
|
|
5
|
+
|
|
6
|
+
class Kiso::Icons::Commands < Thor
|
|
7
|
+
include Thor::Actions
|
|
8
|
+
|
|
9
|
+
SETS_URL = "https://raw.githubusercontent.com/iconify/icon-sets/master/json"
|
|
10
|
+
|
|
11
|
+
def self.exit_on_failure? = false
|
|
12
|
+
|
|
13
|
+
desc "pin SETS...", "Download icon sets to vendor/icons/"
|
|
14
|
+
long_desc <<~DESC
|
|
15
|
+
Downloads Iconify JSON files for the specified icon sets to vendor/icons/.
|
|
16
|
+
Commit these files to git for production use (like importmap-rails vendor pattern).
|
|
17
|
+
|
|
18
|
+
Example:
|
|
19
|
+
$ bin/kiso-icons pin lucide
|
|
20
|
+
$ bin/kiso-icons pin heroicons mdi tabler
|
|
21
|
+
DESC
|
|
22
|
+
def pin(*sets)
|
|
23
|
+
if sets.empty?
|
|
24
|
+
say "Usage: bin/kiso-icons pin SET [SET...]", :red
|
|
25
|
+
say ""
|
|
26
|
+
say "Example: bin/kiso-icons pin lucide heroicons"
|
|
27
|
+
say "Browse sets: https://icon-sets.iconify.design/"
|
|
28
|
+
exit 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
vendor_dir = vendor_path
|
|
32
|
+
FileUtils.mkdir_p(vendor_dir)
|
|
33
|
+
|
|
34
|
+
sets.each { |set_name| pin_set(set_name, vendor_dir) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
desc "unpin SET", "Remove a vendored icon set"
|
|
38
|
+
def unpin(set_name)
|
|
39
|
+
path = File.join(vendor_path, "#{set_name}.json")
|
|
40
|
+
|
|
41
|
+
unless File.exist?(path)
|
|
42
|
+
say " not found #{set_name} is not pinned", :red
|
|
43
|
+
return
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
File.delete(path)
|
|
47
|
+
say " remove vendor/icons/#{set_name}.json", :green
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
desc "pristine", "Re-download all pinned icon sets"
|
|
51
|
+
def pristine
|
|
52
|
+
sets = vendored_sets
|
|
53
|
+
if sets.empty?
|
|
54
|
+
say "No icon sets pinned. Pin one with: bin/kiso-icons pin lucide", :yellow
|
|
55
|
+
return
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
vendor_dir = vendor_path
|
|
59
|
+
say "Re-downloading #{sets.size} pinned set(s)..."
|
|
60
|
+
sets.each { |set_name| pin_set(set_name, vendor_dir, overwrite: true) }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
desc "list", "Show pinned icon sets"
|
|
64
|
+
def list
|
|
65
|
+
sets = vendored_sets
|
|
66
|
+
if sets.empty?
|
|
67
|
+
say "No icon sets pinned.", :yellow
|
|
68
|
+
say ""
|
|
69
|
+
say "Pin a set: bin/kiso-icons pin lucide"
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
say "Pinned icon sets (vendor/icons/):", :cyan
|
|
74
|
+
say ""
|
|
75
|
+
|
|
76
|
+
sets.each do |set_name|
|
|
77
|
+
path = File.join(vendor_path, "#{set_name}.json")
|
|
78
|
+
size_kb = (File.size(path) / 1024.0).round(1)
|
|
79
|
+
data = JSON.parse(File.read(path))
|
|
80
|
+
icon_count = (data["icons"] || {}).size
|
|
81
|
+
display_name = data.dig("info", "name") || set_name
|
|
82
|
+
|
|
83
|
+
say " #{set_name.ljust(20)} #{icon_count.to_s.rjust(6)} icons #{size_kb.to_s.rjust(8)} KB (#{display_name})"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def pin_set(set_name, vendor_dir, overwrite: false)
|
|
90
|
+
dest = File.join(vendor_dir, "#{set_name}.json")
|
|
91
|
+
|
|
92
|
+
if File.exist?(dest) && !overwrite
|
|
93
|
+
say " exists vendor/icons/#{set_name}.json (use `pristine` to re-download)", :yellow
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
url = "#{SETS_URL}/#{set_name}.json"
|
|
98
|
+
say " fetch #{url}"
|
|
99
|
+
|
|
100
|
+
body = download(url)
|
|
101
|
+
if body.nil?
|
|
102
|
+
say " error Could not download #{set_name}. Check the set name.", :red
|
|
103
|
+
say " Browse sets: https://icon-sets.iconify.design/"
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
body = body.force_encoding("UTF-8")
|
|
108
|
+
|
|
109
|
+
data = JSON.parse(body)
|
|
110
|
+
unless data["icons"]
|
|
111
|
+
say " error #{set_name}.json has no 'icons' key -- invalid Iconify format", :red
|
|
112
|
+
return
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
File.write(dest, body)
|
|
116
|
+
icon_count = data["icons"].size
|
|
117
|
+
size_kb = (body.bytesize / 1024.0).round(1)
|
|
118
|
+
say " pin vendor/icons/#{set_name}.json (#{icon_count} icons, #{size_kb} KB)", :green
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def download(url, redirect_limit = 5)
|
|
122
|
+
raise "Too many redirects" if redirect_limit == 0
|
|
123
|
+
|
|
124
|
+
uri = URI(url)
|
|
125
|
+
response = Net::HTTP.get_response(uri)
|
|
126
|
+
case response
|
|
127
|
+
when Net::HTTPSuccess then response.body
|
|
128
|
+
when Net::HTTPRedirection then download(response["location"], redirect_limit - 1)
|
|
129
|
+
end
|
|
130
|
+
rescue SocketError, Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNREFUSED => e
|
|
131
|
+
say " error Network error: #{e.message}", :red
|
|
132
|
+
nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def vendor_path
|
|
136
|
+
base = if defined?(Rails) && Rails.root
|
|
137
|
+
Rails.root.to_s
|
|
138
|
+
else
|
|
139
|
+
Dir.pwd
|
|
140
|
+
end
|
|
141
|
+
File.join(base, Kiso::Icons.configuration.vendor_path)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def vendored_sets
|
|
145
|
+
Dir.glob(File.join(vendor_path, "*.json"))
|
|
146
|
+
.map { |f| File.basename(f, ".json") }
|
|
147
|
+
.sort
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Icons
|
|
5
|
+
class Configuration
|
|
6
|
+
attr_accessor :default_set, :vendor_path, :fallback_to_api
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@default_set = "lucide"
|
|
10
|
+
@vendor_path = "vendor/icons"
|
|
11
|
+
@fallback_to_api = defined?(Rails) ? Rails.env.development? : false
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
|
|
5
|
+
module Kiso
|
|
6
|
+
module Icons
|
|
7
|
+
module Helper
|
|
8
|
+
# Renders an inline SVG icon from Iconify icon sets.
|
|
9
|
+
#
|
|
10
|
+
# kiso_icon_tag("lucide:check")
|
|
11
|
+
# kiso_icon_tag("check") # uses default set (lucide)
|
|
12
|
+
# kiso_icon_tag("check", class: "w-5 h-5") # pass any CSS classes
|
|
13
|
+
# kiso_icon_tag("check", aria: { label: "Done" }) # accessible icon
|
|
14
|
+
#
|
|
15
|
+
def kiso_icon_tag(name, **options)
|
|
16
|
+
icon_data = Kiso::Icons.resolve(name.to_s)
|
|
17
|
+
|
|
18
|
+
unless icon_data
|
|
19
|
+
if defined?(Rails) && Rails.env.development?
|
|
20
|
+
return safe_string("<!-- kiso-icons: '#{ERB::Util.html_escape(name)}' not found -->")
|
|
21
|
+
end
|
|
22
|
+
return safe_string("")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Kiso::Icons::Renderer.render(icon_data, css_class: options.delete(:class), **options)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def safe_string(str)
|
|
31
|
+
if defined?(ActiveSupport::SafeBuffer)
|
|
32
|
+
ActiveSupport::SafeBuffer.new(str)
|
|
33
|
+
else
|
|
34
|
+
str
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "kiso/icons/helper"
|
|
4
|
+
|
|
5
|
+
module Kiso
|
|
6
|
+
module Icons
|
|
7
|
+
class Railtie < ::Rails::Railtie
|
|
8
|
+
initializer "kiso_icons.configure" do |_app|
|
|
9
|
+
Kiso::Icons.configure do |config|
|
|
10
|
+
config.fallback_to_api = Rails.env.development? || Rails.env.test?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
initializer "kiso_icons.helpers" do
|
|
15
|
+
ActiveSupport.on_load(:action_view) do
|
|
16
|
+
include Kiso::Icons::Helper
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
rake_tasks do
|
|
21
|
+
load "tasks/kiso_icons_tasks.rake"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Icons
|
|
5
|
+
class Renderer
|
|
6
|
+
class << self
|
|
7
|
+
def render(icon_data, css_class: nil, **options)
|
|
8
|
+
body = icon_data[:body]
|
|
9
|
+
width = icon_data[:width]
|
|
10
|
+
height = icon_data[:height]
|
|
11
|
+
|
|
12
|
+
attrs = {
|
|
13
|
+
"xmlns" => "http://www.w3.org/2000/svg",
|
|
14
|
+
"viewBox" => "0 0 #{width} #{height}",
|
|
15
|
+
"width" => "1em",
|
|
16
|
+
"height" => "1em",
|
|
17
|
+
"aria-hidden" => "true",
|
|
18
|
+
"fill" => "none"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
attrs["class"] = css_class if css_class && !css_class.empty?
|
|
22
|
+
|
|
23
|
+
options.each do |key, value|
|
|
24
|
+
if key == :data && value.is_a?(Hash)
|
|
25
|
+
value.each { |k, v| attrs["data-#{k.to_s.tr("_", "-")}"] = v.to_s }
|
|
26
|
+
elsif key == :aria && value.is_a?(Hash)
|
|
27
|
+
value.each { |k, v| attrs["aria-#{k.to_s.tr("_", "-")}"] = v.to_s }
|
|
28
|
+
else
|
|
29
|
+
attrs[key.to_s.tr("_", "-")] = value.to_s
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if attrs.key?("aria-label")
|
|
34
|
+
attrs.delete("aria-hidden")
|
|
35
|
+
attrs["role"] = "img"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_str = attrs.map { |k, v| %(#{k}="#{escape_attr(v)}") }.join(" ")
|
|
39
|
+
svg = %(<svg #{attr_str}>#{body}</svg>)
|
|
40
|
+
|
|
41
|
+
if defined?(ActiveSupport::SafeBuffer)
|
|
42
|
+
ActiveSupport::SafeBuffer.new(svg)
|
|
43
|
+
else
|
|
44
|
+
svg
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def escape_attr(value)
|
|
51
|
+
value.to_s
|
|
52
|
+
.gsub("&", "&")
|
|
53
|
+
.gsub('"', """)
|
|
54
|
+
.gsub("<", "<")
|
|
55
|
+
.gsub(">", ">")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Icons
|
|
5
|
+
class Resolver
|
|
6
|
+
def initialize
|
|
7
|
+
@loaded_sets = {}
|
|
8
|
+
@mutex = Mutex.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def resolve(name)
|
|
12
|
+
set_prefix, icon_name = parse_name(name)
|
|
13
|
+
|
|
14
|
+
# 1. In-memory cache
|
|
15
|
+
cached = Kiso::Icons.cache.get(set_prefix, icon_name)
|
|
16
|
+
return cached if cached
|
|
17
|
+
|
|
18
|
+
# 2. Already-loaded set
|
|
19
|
+
icon_data = resolve_from_loaded_set(set_prefix, icon_name)
|
|
20
|
+
|
|
21
|
+
# 3. Vendored JSON
|
|
22
|
+
icon_data ||= resolve_from_vendor(set_prefix, icon_name)
|
|
23
|
+
|
|
24
|
+
# 4. Bundled (lucide ships in gem)
|
|
25
|
+
icon_data ||= resolve_from_bundled(set_prefix, icon_name)
|
|
26
|
+
|
|
27
|
+
# 5. API fallback (dev only)
|
|
28
|
+
icon_data ||= resolve_from_api(set_prefix, icon_name)
|
|
29
|
+
|
|
30
|
+
Kiso::Icons.cache.set(set_prefix, icon_name, icon_data) if icon_data
|
|
31
|
+
|
|
32
|
+
icon_data
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def clear!
|
|
36
|
+
@mutex.synchronize { @loaded_sets.clear }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def parse_name(name)
|
|
42
|
+
name = name.to_s.strip
|
|
43
|
+
if name.include?(":")
|
|
44
|
+
name.split(":", 2)
|
|
45
|
+
else
|
|
46
|
+
[Kiso::Icons.configuration.default_set, name]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def resolve_from_loaded_set(set_prefix, icon_name)
|
|
51
|
+
set = @mutex.synchronize { @loaded_sets[set_prefix] }
|
|
52
|
+
set&.icon(icon_name)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def resolve_from_vendor(set_prefix, icon_name)
|
|
56
|
+
set = Set.from_vendor(set_prefix)
|
|
57
|
+
return nil unless set
|
|
58
|
+
|
|
59
|
+
@mutex.synchronize { @loaded_sets[set_prefix] = set }
|
|
60
|
+
set.icon(icon_name)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def resolve_from_bundled(set_prefix, icon_name)
|
|
64
|
+
set = Set.from_bundled(set_prefix)
|
|
65
|
+
return nil unless set
|
|
66
|
+
|
|
67
|
+
@mutex.synchronize { @loaded_sets[set_prefix] = set }
|
|
68
|
+
set.icon(icon_name)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def resolve_from_api(set_prefix, icon_name)
|
|
72
|
+
return nil unless Kiso::Icons.configuration.fallback_to_api
|
|
73
|
+
|
|
74
|
+
ApiClient.fetch_icon(set_prefix, icon_name)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "zlib"
|
|
5
|
+
require "stringio"
|
|
6
|
+
require "pathname"
|
|
7
|
+
|
|
8
|
+
module Kiso
|
|
9
|
+
module Icons
|
|
10
|
+
class Set
|
|
11
|
+
attr_reader :prefix, :default_width, :default_height
|
|
12
|
+
|
|
13
|
+
def initialize(prefix:, data:)
|
|
14
|
+
@prefix = prefix
|
|
15
|
+
@icons = data["icons"] || {}
|
|
16
|
+
@aliases = data["aliases"] || {}
|
|
17
|
+
@default_width = data["width"] || 24
|
|
18
|
+
@default_height = data["height"] || 24
|
|
19
|
+
@info = data["info"] || {}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def icon(name)
|
|
23
|
+
if (icon_data = @icons[name])
|
|
24
|
+
return build_icon_data(icon_data)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
resolved_name = resolve_alias(name)
|
|
28
|
+
if resolved_name && (icon_data = @icons[resolved_name])
|
|
29
|
+
alias_data = @aliases[name]
|
|
30
|
+
return build_icon_data(icon_data, alias_transforms: alias_data)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def icon_names
|
|
37
|
+
@icons.keys + @aliases.keys
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def icon_count
|
|
41
|
+
@icons.size
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def display_name
|
|
45
|
+
@info["name"] || @prefix
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class << self
|
|
49
|
+
def from_vendor(prefix)
|
|
50
|
+
path = vendor_path_for(prefix)
|
|
51
|
+
return nil unless File.exist?(path)
|
|
52
|
+
|
|
53
|
+
data = JSON.parse(File.read(path))
|
|
54
|
+
new(prefix: prefix, data: data)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def from_bundled(prefix)
|
|
58
|
+
path = bundled_path_for(prefix)
|
|
59
|
+
return nil unless File.exist?(path)
|
|
60
|
+
|
|
61
|
+
gz_data = File.binread(path)
|
|
62
|
+
json_str = Zlib::GzipReader.new(StringIO.new(gz_data)).read
|
|
63
|
+
data = JSON.parse(json_str)
|
|
64
|
+
new(prefix: prefix, data: data)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def vendor_path_for(prefix)
|
|
68
|
+
base = if defined?(Rails) && Rails.root
|
|
69
|
+
Rails.root
|
|
70
|
+
else
|
|
71
|
+
Pathname.new(Dir.pwd)
|
|
72
|
+
end
|
|
73
|
+
base.join(Kiso::Icons.configuration.vendor_path, "#{prefix}.json").to_s
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def bundled_path_for(prefix)
|
|
77
|
+
File.join(gem_data_path, "#{prefix}.json.gz")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def gem_data_path
|
|
81
|
+
File.expand_path("../../../../data", __FILE__)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def vendored_sets
|
|
85
|
+
pattern = if defined?(Rails) && Rails.root
|
|
86
|
+
Rails.root.join(Kiso::Icons.configuration.vendor_path, "*.json").to_s
|
|
87
|
+
else
|
|
88
|
+
File.join(Dir.pwd, Kiso::Icons.configuration.vendor_path, "*.json")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
Dir.glob(pattern).map { |f| File.basename(f, ".json") }.sort
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def resolve_alias(name, depth: 0)
|
|
98
|
+
return nil if depth > 5
|
|
99
|
+
alias_entry = @aliases[name]
|
|
100
|
+
return nil unless alias_entry
|
|
101
|
+
|
|
102
|
+
parent = alias_entry["parent"]
|
|
103
|
+
return parent if @icons.key?(parent)
|
|
104
|
+
|
|
105
|
+
resolve_alias(parent, depth: depth + 1)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def build_icon_data(icon_data, alias_transforms: nil)
|
|
109
|
+
body = icon_data["body"]
|
|
110
|
+
width = icon_data["width"] || @default_width
|
|
111
|
+
height = icon_data["height"] || @default_height
|
|
112
|
+
|
|
113
|
+
if alias_transforms
|
|
114
|
+
body = apply_transforms(body, alias_transforms, width, height)
|
|
115
|
+
width = alias_transforms["width"] || width
|
|
116
|
+
height = alias_transforms["height"] || height
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
{body: body, width: width, height: height}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def apply_transforms(body, transforms, width, height)
|
|
123
|
+
parts = []
|
|
124
|
+
|
|
125
|
+
if transforms["rotate"]
|
|
126
|
+
degrees = transforms["rotate"] * 90
|
|
127
|
+
parts << "rotate(#{degrees} #{width / 2.0} #{height / 2.0})"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
scale_x = transforms["hFlip"] ? -1 : 1
|
|
131
|
+
scale_y = transforms["vFlip"] ? -1 : 1
|
|
132
|
+
|
|
133
|
+
if scale_x != 1 || scale_y != 1
|
|
134
|
+
tx = transforms["hFlip"] ? width : 0
|
|
135
|
+
ty = transforms["vFlip"] ? height : 0
|
|
136
|
+
parts << "translate(#{tx} #{ty})" if tx != 0 || ty != 0
|
|
137
|
+
parts << "scale(#{scale_x} #{scale_y})"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if parts.any?
|
|
141
|
+
%(<g transform="#{parts.join(" ")}">#{body}</g>)
|
|
142
|
+
else
|
|
143
|
+
body
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
data/lib/kiso/icons.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kiso
|
|
4
|
+
module Icons
|
|
5
|
+
class Error < StandardError; end
|
|
6
|
+
class IconNotFound < Error; end
|
|
7
|
+
class SetNotFound < Error; end
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def configuration
|
|
11
|
+
@configuration ||= Configuration.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def configure
|
|
15
|
+
yield(configuration)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def resolver
|
|
19
|
+
@resolver ||= Resolver.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def cache
|
|
23
|
+
@cache ||= Cache.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def resolve(name)
|
|
27
|
+
resolver.resolve(name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def reset!
|
|
31
|
+
@resolver = nil
|
|
32
|
+
@cache = nil
|
|
33
|
+
@configuration = nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
require "kiso/icons/version"
|
|
40
|
+
require "kiso/icons/configuration"
|
|
41
|
+
require "kiso/icons/cache"
|
|
42
|
+
require "kiso/icons/set"
|
|
43
|
+
require "kiso/icons/resolver"
|
|
44
|
+
require "kiso/icons/renderer"
|
|
45
|
+
require "kiso/icons/api_client"
|
|
46
|
+
require "kiso/icons/railtie" if defined?(Rails::Railtie)
|
data/lib/kiso-icons.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
namespace :kiso_icons do
|
|
2
|
+
desc "Setup kiso-icons for the app"
|
|
3
|
+
task :install do
|
|
4
|
+
previous_location = ENV["LOCATION"]
|
|
5
|
+
ENV["LOCATION"] = File.expand_path("../install/install.rb", __dir__)
|
|
6
|
+
Rake::Task["app:template"].invoke
|
|
7
|
+
ENV["LOCATION"] = previous_location
|
|
8
|
+
end
|
|
9
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: kiso-icons
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0.pre
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Steve Clarke
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: railties
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '8.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '8.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: activesupport
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '8.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '8.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: actionpack
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '8.0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '8.0'
|
|
54
|
+
description: Pin any of Iconify's 224 icon sets (299k icons) to vendor/icons/. Inline
|
|
55
|
+
SVG rendering, zero JavaScript, vendored for production.
|
|
56
|
+
email:
|
|
57
|
+
- steve@sevenview.ca
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- CHANGELOG.md
|
|
63
|
+
- MIT-LICENSE
|
|
64
|
+
- README.md
|
|
65
|
+
- Rakefile
|
|
66
|
+
- data/lucide.json.gz
|
|
67
|
+
- lib/install/bin/kiso-icons
|
|
68
|
+
- lib/install/install.rb
|
|
69
|
+
- lib/kiso-icons.rb
|
|
70
|
+
- lib/kiso/icons.rb
|
|
71
|
+
- lib/kiso/icons/api_client.rb
|
|
72
|
+
- lib/kiso/icons/cache.rb
|
|
73
|
+
- lib/kiso/icons/commands.rb
|
|
74
|
+
- lib/kiso/icons/configuration.rb
|
|
75
|
+
- lib/kiso/icons/helper.rb
|
|
76
|
+
- lib/kiso/icons/railtie.rb
|
|
77
|
+
- lib/kiso/icons/renderer.rb
|
|
78
|
+
- lib/kiso/icons/resolver.rb
|
|
79
|
+
- lib/kiso/icons/set.rb
|
|
80
|
+
- lib/kiso/icons/version.rb
|
|
81
|
+
- lib/tasks/kiso_icons_tasks.rake
|
|
82
|
+
homepage: https://github.com/steveclarke/kiso-icons
|
|
83
|
+
licenses:
|
|
84
|
+
- MIT
|
|
85
|
+
metadata:
|
|
86
|
+
homepage_uri: https://github.com/steveclarke/kiso-icons
|
|
87
|
+
source_code_uri: https://github.com/steveclarke/kiso-icons
|
|
88
|
+
changelog_uri: https://github.com/steveclarke/kiso-icons/blob/master/CHANGELOG.md
|
|
89
|
+
bug_tracker_uri: https://github.com/steveclarke/kiso-icons/issues
|
|
90
|
+
rubygems_mfa_required: 'true'
|
|
91
|
+
allowed_push_host: https://rubygems.org
|
|
92
|
+
rdoc_options: []
|
|
93
|
+
require_paths:
|
|
94
|
+
- lib
|
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '3.2'
|
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: '0'
|
|
105
|
+
requirements: []
|
|
106
|
+
rubygems_version: 3.6.9
|
|
107
|
+
specification_version: 4
|
|
108
|
+
summary: Iconify icons for Rails
|
|
109
|
+
test_files: []
|