unmagic-icon 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +1 -0
- data/lib/unmagic/icon/library/source/lobe_icons.rb +24 -0
- data/lib/unmagic/icon/library/source.rb +64 -5
- data/lib/unmagic/icon/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66fe0a90a06ca3989154088d6e1d8cda87f6f1055d9b0ddf368ee2e9a054fd2f
|
|
4
|
+
data.tar.gz: fb7ad24d2a2c4d56a9dc4246751ff12542424ebc392bddba9be78f8f3420bc47
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5e2c6186cb26a61779090c520930a9941725db13d2807df6a61ecad308debecaf86c928ca9e4b5bc6ca3dd3768b16fa1456ae42802a34bd6a90ab8963db3b71
|
|
7
|
+
data.tar.gz: 65e389aa2b586335518e70919aa560601a8157cc8ef21bab78ed8ab52fdce9dc0ba35add14410a737d4fbc9690fafe673cc7d5a1ec9ec14aa31dd64e2649a694
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.0] - 2026-07-31
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- New downloadable icon library: `lobe-icons` (AI/LLM brand logos from
|
|
14
|
+
LobeHub, with `-color` and `-text` variants alongside each bare mark)
|
|
15
|
+
|
|
16
|
+
## [0.2.1] - 2026-07-14
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Archives are now extracted in pure Ruby (rubyzip for zips, stdlib
|
|
20
|
+
`Gem::Package::TarReader`/`Zlib` for tarballs) instead of shelling out to
|
|
21
|
+
`unzip`/`tar`, so `unmagic:icons:install` works in minimal containers —
|
|
22
|
+
such as Rails' default slim Docker image — where those binaries aren't
|
|
23
|
+
installed. Extraction also guards against zip-slip path traversal.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- Runtime dependency on `rubyzip` (>= 2.3)
|
|
27
|
+
|
|
10
28
|
## [0.2.0] - 2026-06-22
|
|
11
29
|
|
|
12
30
|
### Added
|
|
@@ -41,6 +59,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
41
59
|
hooks into `assets:precompile`) and `unmagic:icons:download[library]`
|
|
42
60
|
- `Unmagic::Icon::Web`, a Rack app for browsing the configured icon libraries
|
|
43
61
|
|
|
44
|
-
[Unreleased]: https://github.com/unreasonable-magic/unmagic-icon/compare/v0.
|
|
62
|
+
[Unreleased]: https://github.com/unreasonable-magic/unmagic-icon/compare/v0.3.0...HEAD
|
|
63
|
+
[0.3.0]: https://github.com/unreasonable-magic/unmagic-icon/compare/v0.2.1...v0.3.0
|
|
64
|
+
[0.2.1]: https://github.com/unreasonable-magic/unmagic-icon/compare/v0.2.0...v0.2.1
|
|
45
65
|
[0.2.0]: https://github.com/unreasonable-magic/unmagic-icon/compare/v0.1.0...v0.2.0
|
|
46
66
|
[0.1.0]: https://github.com/unreasonable-magic/unmagic-icon/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -133,6 +133,7 @@ Available libraries:
|
|
|
133
133
|
| `iconoir` | Iconoir | Free open source icons designed on a 24x24 grid |
|
|
134
134
|
| `material-design-icons` | Material Design Icons | 7400+ Material Design icons (Pictogrammers @mdi) |
|
|
135
135
|
| `phosphor` | Phosphor Icons | Flexible icon family with six weights (thin to fill, plus duotone) |
|
|
136
|
+
| `lobe-icons` | Lobe Icons | Popular AI / LLM model brand logos and icons |
|
|
136
137
|
|
|
137
138
|
### Browsing icons
|
|
138
139
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Unmagic
|
|
4
|
+
class Icon
|
|
5
|
+
class Library
|
|
6
|
+
class Source
|
|
7
|
+
# LobeHub's AI/LLM brand logos, sourced from the static-svg npm package
|
|
8
|
+
# rather than the repo (the repo only ships React components). Each brand
|
|
9
|
+
# comes in up to three variants, distinguished by filename suffix: the
|
|
10
|
+
# bare mark (openai), the full-colour mark (openai-color), and the
|
|
11
|
+
# wordmark (openai-text).
|
|
12
|
+
class LobeIcons < Source
|
|
13
|
+
key :"lobe-icons"
|
|
14
|
+
title "Lobe Icons"
|
|
15
|
+
description "Popular AI / LLM model brand logos and icons"
|
|
16
|
+
url "https://registry.npmjs.org/@lobehub/icons-static-svg/-/icons-static-svg-1.94.0.tgz"
|
|
17
|
+
archive :tgz
|
|
18
|
+
dir "lobe-icons"
|
|
19
|
+
extract "package/icons/*.svg"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -6,7 +6,8 @@ require "json"
|
|
|
6
6
|
require "pathname"
|
|
7
7
|
require "fileutils"
|
|
8
8
|
require "tmpdir"
|
|
9
|
-
require "
|
|
9
|
+
require "zlib"
|
|
10
|
+
require "rubygems/package"
|
|
10
11
|
|
|
11
12
|
# Terminal progress is a nicety, not a requirement. The downloader runs fine
|
|
12
13
|
# (with plain output) when these sibling gems aren't installed.
|
|
@@ -211,19 +212,76 @@ module Unmagic
|
|
|
211
212
|
end
|
|
212
213
|
end
|
|
213
214
|
|
|
215
|
+
# Pure-Ruby extraction — no `unzip`/`tar` binaries required, so this
|
|
216
|
+
# works in minimal containers (e.g. Rails' default slim Docker image).
|
|
214
217
|
def extract_archive(archive_path, destination, type)
|
|
215
218
|
case type
|
|
216
219
|
when :zip
|
|
217
|
-
|
|
218
|
-
raise ExtractionError, "Failed to extract zip: #{stderr}" unless status.success?
|
|
220
|
+
extract_zip(archive_path, destination)
|
|
219
221
|
when :tgz, :tar
|
|
220
|
-
|
|
221
|
-
raise ExtractionError, "Failed to extract tar: #{stderr}" unless status.success?
|
|
222
|
+
extract_tar(archive_path, destination)
|
|
222
223
|
else
|
|
223
224
|
raise ExtractionError, "Unknown archive type: #{type}"
|
|
224
225
|
end
|
|
225
226
|
end
|
|
226
227
|
|
|
228
|
+
def extract_zip(archive_path, destination)
|
|
229
|
+
require "zip"
|
|
230
|
+
|
|
231
|
+
Zip::File.open(archive_path) do |zip|
|
|
232
|
+
zip.each do |entry|
|
|
233
|
+
path = safe_extraction_path(entry.name, destination)
|
|
234
|
+
|
|
235
|
+
if entry.directory?
|
|
236
|
+
FileUtils.mkdir_p(path)
|
|
237
|
+
elsif entry.file?
|
|
238
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
239
|
+
entry.get_input_stream do |input|
|
|
240
|
+
File.open(path, "wb") { |file| IO.copy_stream(input, file) }
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
rescue Zip::Error => e
|
|
246
|
+
raise ExtractionError, "Failed to extract zip: #{e.message}"
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
GZIP_MAGIC = "\x1f\x8b".b
|
|
250
|
+
|
|
251
|
+
def extract_tar(archive_path, destination)
|
|
252
|
+
File.open(archive_path, "rb") do |file|
|
|
253
|
+
stream = file.read(2) == GZIP_MAGIC ? Zlib::GzipReader.new(file.tap(&:rewind)) : file.tap(&:rewind)
|
|
254
|
+
|
|
255
|
+
Gem::Package::TarReader.new(stream) do |tar|
|
|
256
|
+
tar.each do |entry|
|
|
257
|
+
path = safe_extraction_path(entry.full_name, destination)
|
|
258
|
+
|
|
259
|
+
if entry.directory?
|
|
260
|
+
FileUtils.mkdir_p(path)
|
|
261
|
+
elsif entry.file?
|
|
262
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
263
|
+
File.open(path, "wb") { |output| IO.copy_stream(entry, output) }
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
rescue Zlib::Error, Gem::Package::Error => e
|
|
269
|
+
raise ExtractionError, "Failed to extract tar: #{e.message}"
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Guards against zip-slip: entries like "../../etc/passwd" must not
|
|
273
|
+
# escape the extraction directory.
|
|
274
|
+
def safe_extraction_path(entry_name, destination)
|
|
275
|
+
destination = File.expand_path(destination)
|
|
276
|
+
path = File.expand_path(entry_name, destination)
|
|
277
|
+
|
|
278
|
+
unless path == destination || path.start_with?(destination + File::SEPARATOR)
|
|
279
|
+
raise ExtractionError, "Archive entry escapes extraction directory: #{entry_name}"
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
path
|
|
283
|
+
end
|
|
284
|
+
|
|
227
285
|
def count_svgs(directory)
|
|
228
286
|
Dir.glob(File.join(directory, "**", "*.svg")).size
|
|
229
287
|
end
|
|
@@ -246,3 +304,4 @@ require_relative "source/octicons"
|
|
|
246
304
|
require_relative "source/iconoir"
|
|
247
305
|
require_relative "source/material_design_icons"
|
|
248
306
|
require_relative "source/phosphor"
|
|
307
|
+
require_relative "source/lobe_icons"
|
data/lib/unmagic/icon/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: unmagic-icon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Keith Pitt
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -52,6 +52,20 @@ dependencies:
|
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: 1.8.5
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rubyzip
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.3'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '2.3'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: rspec
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -107,6 +121,7 @@ files:
|
|
|
107
121
|
- lib/unmagic/icon/library/source/feather.rb
|
|
108
122
|
- lib/unmagic/icon/library/source/heroicons.rb
|
|
109
123
|
- lib/unmagic/icon/library/source/iconoir.rb
|
|
124
|
+
- lib/unmagic/icon/library/source/lobe_icons.rb
|
|
110
125
|
- lib/unmagic/icon/library/source/lucide.rb
|
|
111
126
|
- lib/unmagic/icon/library/source/material_design_icons.rb
|
|
112
127
|
- lib/unmagic/icon/library/source/material_file_icons.rb
|