stylicon 0.1.5 → 0.2.1

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: b7e165f82e296d7dcf81e60bdc3e1fab621503b8495737514f274d02f8727d75
4
- data.tar.gz: 81c154b6671858731633933609302149b5d8e40aaadc713131fc1c4cf1ec054f
3
+ metadata.gz: 38690808a8ba07f5bfb35310eee321d2f2eaec78799384847d756ba6661800cc
4
+ data.tar.gz: c438a87c7cc767734786e4694b50d0384e938447f0fa53c5c039f6febcad4e2f
5
5
  SHA512:
6
- metadata.gz: c1e3e1ff72864bc69c2995afaaab7b151da01fd19a962ba3b6a945fdb97c4cc65fd23b6822b9d3d2490462f008f222bdb96454892b431c68c4bb9dba28b92794
7
- data.tar.gz: 394e189d075a7e81031d3a566982efb0ab2b688c81dc3100fd472c5a05434083112b59d750d37ece56f32e6e3d393e587ba116781720ac53f0f9d90300c0fb9e
6
+ metadata.gz: dba8bcf1152535c48c72c3bb4cd81ccb0f603cad3314e04fe0284ecf2547082d42884e07572a9b4c34b71b6a1da2433d730ae5e640dd0c4ca6d2a3fe303851c4
7
+ data.tar.gz: bea0b94eaa5ea0b1f9f29d898154ad31620f00b94bb7e3d900380141db0df79b97cb30f4f987aa5c3607fb6a1c5a9dd5a05e7757b41ce7b39ff4f04bdfa1980a
data/CLAUDE.md ADDED
@@ -0,0 +1,28 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ### User Background
6
+ - Junior Ruby on Rails developer
7
+ - Interested in front end on ruby on rails (hotwire stack)
8
+ - Interested in learning deeper on ruby
9
+ - Interested on learning about backend architecture
10
+ - Interested in learning how to write clean beautiful code
11
+
12
+ ### User Preferences
13
+ - I want to write code myself, I think that's the best way to learn
14
+ - Don't write code directly on the file unless told you so explicitly
15
+ - You can give me code examples for me to have an idea and then write the code myself
16
+ - I'm learning so if you see the opportunity to explain some key concept, go ahead!
17
+ - Don't treat me formally, I hate formality
18
+ - I'm a Junior developer who is eager to learn. Let me know when I make mistakes or if my code is shitty. Don't treat me nicely, be harsh and critical.
19
+ - Go to the point, don't be verbose or try to sound smart.
20
+
21
+ ### Code expectations
22
+ - I want to write the code but you can suggest new things, but I'll write it myself
23
+ - Feel free to suggest improvements
24
+ - Use good practices, like clean code.
25
+ - I want to learn about engineering on applications, feel free to suggest improvements and explain them theorically.
26
+ - Feel free to suggest resources to learn.
27
+ - When I ask you to write documentation do it in a coloquial way, or give me ideas, like points I should cover to explain stuff to others.
28
+ - Review my code, be honest, be brutal. If I'm leaving something behind let me know.
data/README.md CHANGED
@@ -1,28 +1,413 @@
1
1
  # Stylicon
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ **High-Performance Icon System** - Generate lightning-fast CSS icon classes from SVG files. Dramatically improve your application's performance by replacing inline SVGs with cacheable, optimized CSS classes.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/stylicon`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ ## Performance First.
6
6
 
7
- ## Installation
7
+ Traditional icon approaches hurt performance:
8
+
9
+ ```html
10
+ <!-- SLOW: Inline SVG (repeated 50 times = 50x the code) -->
11
+ <svg class="icon" viewBox="0 0 24 24">
12
+ <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25z"/>
13
+ </svg>
14
+ ```
15
+
16
+ Stylicon generates **cacheable CSS classes**:
17
+
18
+ ```html
19
+ <!-- FAST: Single CSS class -->
20
+ <i class="icon-edit"></i>
21
+ ```
22
+
23
+ ## Performance Benchmarks
24
+
25
+ I tested Stylicon against traditional SVG approaches to see if the performance claims hold up.
26
+
27
+ ### Test Setup
28
+ - Users table with 100 rows, 3 action icons per row (300 icons total)
29
+ - Tested with `oha` HTTP load tester: 100 requests, 10 concurrent connections
30
+ - Rails 7 development server, local environment
31
+ - Real-world scenario: Edit, Show, Delete icons
8
32
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
33
+ ### Results
10
34
 
11
- Install the gem and add to the application's Gemfile by executing:
35
+ | Approach | Requests/sec | Avg Response Time | Total Payload | HTTP Requests |
36
+ |----------|-------------|------------------|---------------|---------------|
37
+ | Stylicon CSS | 99.7 | 96.5ms | 49.79 KiB | 2 |
38
+ | Inline SVG | 98.0 | 98.4ms | 256.54 KiB | 1 |
39
+ | Rails image_tag | 32.9 | 294.1ms | 71.47 KiB | 301 |
40
+
41
+ ### Analysis
42
+
43
+ **Server Performance**
44
+ Stylicon handles 3x more requests per second than the Rails image_tag approach. The difference comes from HTTP
45
+ request overhead - serving 300 individual SVG files per page puts significant load on the Rails server.
46
+
47
+ **Payload Size**
48
+ Stylicon generates the smallest payload at under 50 KiB. Inline SVG creates massive HTML files (256 KiB) because the
49
+ same SVG markup gets repeated 100 times. This affects loading speed, especially on slower connections.
50
+
51
+ **HTTP Requests**
52
+ The Rails image_tag approach creates 301 HTTP requests per page load (1 for HTML + 300 for individual SVGs).
53
+ Stylicon uses just 2 requests - the HTML and one cacheable CSS file.
54
+
55
+ **Caching Benefits**
56
+ The CSS file generated by Stylicon gets cached by browsers, so subsequent page loads and navigation only require the
57
+ HTML request. This compounds the performance advantage over time
58
+
59
+ ## Features
60
+
61
+ - 🎨 **CSS Generation**: Convert SVG files to optimized CSS classes with base64 encoding
62
+ - ⚡ **Performance Focused**: Cacheable CSS instead of bloated inline SVG
63
+ - 🔄 **SVG Transformation**: Transform individual or multiple SVG files with styling options
64
+ - 📁 **Batch Processing**: Process entire folders or glob patterns of SVG files
65
+ - 🛠️ **Customizable**: Apply fills, strokes, dimensions, styles, and classes
66
+ - 📦 **Bundle Optimization**: Generate single CSS file for all icons
67
+
68
+ ## Installation
69
+
70
+ Install the gem by executing:
12
71
 
13
72
  ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
73
+ gem install stylicon
15
74
  ```
16
75
 
17
- If bundler is not being used to manage dependencies, install the gem by executing:
76
+ Or add it to your Gemfile:
18
77
 
19
78
  ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
79
+ bundle add stylicon
21
80
  ```
22
81
 
23
82
  ## Usage
24
83
 
25
- TODO: Write usage instructions here
84
+ Stylicon provides three main modes of operation:
85
+
86
+ ### 1. 🚀 CSS Generation (Recommended for Performance)
87
+
88
+ Generate high-performance CSS classes from SVG files:
89
+
90
+ ```bash
91
+ stylicon [config.yml] [output.css]
92
+ ```
93
+
94
+ **Example:**
95
+ ```bash
96
+ stylicon icons.yml stylicon.css
97
+ ```
98
+
99
+ Create an `icons.yml` configuration file:
100
+ ```yaml
101
+ # icons.yml - Configuration for CSS generation
102
+ edit:
103
+ path: icons/edit.svg
104
+ class: ".icon-edit"
105
+ background: "#333"
106
+
107
+ user:
108
+ path: icons/user.svg
109
+ class: [".icon-user", ".user-icon"]
110
+ background: "currentColor"
111
+
112
+ home:
113
+ path: icons/home.svg
114
+ class: ".icon-home"
115
+ # background optional - will use mask mode
116
+
117
+ delete:
118
+ path: icons/delete.svg
119
+ class: ".icon-delete"
120
+ background: "#e74c3c"
121
+ ```
122
+
123
+ This creates a **single cacheable CSS file** with all your icons as base64-encoded background images:
124
+
125
+ ```css
126
+ .icon-edit {
127
+ -webkit-mask-image: url("data:image/svg+xml;base64,PHN2Zy...");
128
+ -webkit-mask-repeat: no-repeat;
129
+ -webkit-mask-size: contain;
130
+ -webkit-mask-position: center;
131
+ display: inline-block;
132
+ background-color: #333;
133
+ }
134
+
135
+ .icon-user, .user-icon {
136
+ -webkit-mask-image: url("data:image/svg+xml;base64,PHN2Zy...");
137
+ -webkit-mask-repeat: no-repeat;
138
+ -webkit-mask-size: contain;
139
+ -webkit-mask-position: center;
140
+ display: inline-block;
141
+ background-color: currentColor;
142
+ }
143
+ ```
144
+
145
+ **HTML Usage:**
146
+ ```html
147
+ <!-- Lightning fast, cacheable icons -->
148
+ <i class="icon-user"></i>
149
+ <i class="icon-edit"></i>
150
+ <i class="icon-delete"></i>
151
+ ```
152
+
153
+ ### 2. Single SVG Transformation
154
+
155
+ Transform a single SVG file with custom styling:
156
+
157
+ ```bash
158
+ stylicon --transform-svg input.svg --out output.svg [options]
159
+ ```
160
+
161
+ **Example:**
162
+ ```bash
163
+ stylicon --transform-svg icon.svg --out styled-icon.svg --fill red --width 32 --height 32 --classes "icon small"
164
+ ```
165
+
166
+ ### 3. Batch SVG Transformation
167
+
168
+ Transform multiple SVG files at once for consistent theming:
169
+
170
+ #### Transform entire folder:
171
+ ```bash
172
+ stylicon --input-folder source/ --out destination/ [options]
173
+ ```
174
+
175
+ #### Transform using glob patterns:
176
+ -```bash
177
+ stylicon --transform-svg "icons/*.svg" --out transformed/ [options]
178
+ ```
179
+
180
+ **Examples:**
181
+ ```bash
182
+ # Transform all SVGs in icons/ folder
183
+ stylicon --input-folder icons/ --out transformed/ --fill blue --width 48
184
+
185
+ # Transform specific pattern
186
+ stylicon --transform-svg "assets/icons/user-*.svg" --out output/ --stroke red --classes "icon user"
187
+
188
+ # Transform all SVGs recursively
189
+ stylicon --transform-svg "**/*.svg" --out flattened/ --height 24 --width 24
190
+ ```
191
+
192
+ ## Command Line Options
193
+
194
+ ### Core Options
195
+
196
+ | Option | Description | Example |
197
+ |--------|-------------|---------|
198
+ | `--transform-svg INPUT` | Transform single SVG or pattern | `--transform-svg icon.svg` |
199
+ | `--out OUTPUT` | Output file/directory | `--out transformed/` |
200
+ | `--input-folder FOLDER` | Input folder for batch processing | `--input-folder icons/` |
201
+
202
+ ### Styling Options
203
+
204
+ | Option | Description | Example | Effect |
205
+ |--------|-------------|---------|--------|
206
+ | `--fill COLOR` | Set fill color | `--fill red` | Changes fill attribute on elements |
207
+ | `--stroke COLOR` | Set stroke color | `--stroke blue` | Changes stroke attribute on elements |
208
+ | `--width SIZE` | Set width | `--width 32` | Sets SVG width attribute |
209
+ | `--height SIZE` | Set height | `--height 32` | Sets SVG height attribute |
210
+ | `--style STYLE` | Add CSS style | `--style "color: green;"` | Adds style attribute to SVG |
211
+ | `--classes CLASSES` | Add CSS classes | `--classes "icon small"` | Adds class attribute to SVG |
212
+
213
+ ## Examples
214
+
215
+ ### Basic SVG Transformation
216
+
217
+ ```bash
218
+ # Add red fill and resize to 24x24
219
+ stylicon --transform-svg icon.svg --out icon-red.svg --fill red --width 24 --height 24
220
+ ```
221
+
222
+ **Input:**
223
+ ```xml
224
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
225
+ <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25z"/>
226
+ </svg>
227
+ ```
228
+
229
+ **Output:**
230
+ ```xml
231
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
232
+ <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25z" fill="red"/>
233
+ </svg>
234
+ ```
235
+
236
+ ### Batch Processing with Styling
237
+
238
+ ```bash
239
+ # Transform all SVGs in icons/ folder with consistent styling
240
+ stylicon --input-folder icons/ --out themed/ --fill "#333" --classes "icon theme-dark" --width 20 --height 20
241
+ ```
242
+
243
+ This will:
244
+ - Process all `.svg` files in the `icons/` folder
245
+ - Apply dark fill color `#333`
246
+ - Add classes `icon theme-dark`
247
+ - Resize all icons to 20x20 pixels
248
+ - Save to `themed/` directory with original filenames
249
+
250
+ ### Pattern-Based Processing
251
+
252
+ ```bash
253
+ # Transform only user-related icons
254
+ stylicon --transform-svg "icons/user-*.svg" --out user-icons/ --stroke blue --classes "user-icon"
255
+
256
+ # Transform all SVGs in any subdirectory
257
+ stylicon --transform-svg "**/social-*.svg" --out social/ --fill currentColor --width 16
258
+ ```
259
+
260
+ ### Complex Styling
261
+
262
+ ```bash
263
+ # Apply multiple style attributes
264
+ stylicon --transform-svg logo.svg --out styled-logo.svg \
265
+ --fill "#FF6B6B" \
266
+ --stroke "#4ECDC4" \
267
+ --width 64 \
268
+ --height 64 \
269
+ --style "filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.3));" \
270
+ --classes "logo featured"
271
+ ```
272
+
273
+ ## Performance Optimization Examples
274
+
275
+ ### High-Performance Icon System
276
+ ```bash
277
+ # Generate cacheable icon CSS for maximum performance
278
+ stylicon icons.yml icons.css
279
+
280
+ # Result: Single 45KB CSS file replaces 2MB of inline SVG
281
+ ```
282
+
283
+ ### Theme Variations (Performance-Optimized)
284
+ ```bash
285
+ # Generate separate cached CSS files for each theme
286
+ stylicon --input-folder icons/ --out icons-dark.css --fill "#ffffff" --classes "icon dark"
287
+ stylicon --input-folder icons/ --out icons-light.css --fill "#000000" --classes "icon light"
288
+
289
+ # Users download only the theme they need, cached forever
290
+ ```
291
+
292
+ ### Size Variants for Responsive Performance
293
+ ```bash
294
+ # Small icons for mobile (minimal bandwidth)
295
+ stylicon --transform-svg "icons/*.svg" --out icons-sm/ --width 16 --height 16 --classes "icon icon-sm"
296
+
297
+ # Large icons for desktop (cached separately)
298
+ stylicon --transform-svg "icons/*.svg" --out icons-lg/ --width 48 --height 48 --classes "icon icon-lg"
299
+ ```
300
+
301
+ ## Performance Best Practices
302
+
303
+ ### 1. Use CSS Generation for Production
304
+ ```bash
305
+ # BEST: Single cached CSS file
306
+ stylicon icons.yml production-icons.css
307
+
308
+ # AVOID: Individual icon transformations for web use
309
+ ```
310
+
311
+ ### 2. Optimize for HTTP/2
312
+ ```bash
313
+ # Generate size-specific CSS files for optimal caching
314
+ stylicon icons.yml icons-16.css --width 16 --height 16
315
+ stylicon icons.yml icons-24.css --width 24 --height 24
316
+ stylicon icons.yml icons-32.css --width 32 --height 32
317
+ ```
318
+
319
+ ### 3. Bundle Optimization
320
+ ```bash
321
+ # Create production bundle
322
+ stylicon --input-folder src/icons/ --out dist/icons.css \
323
+ --fill currentColor \
324
+ --classes "icon" \
325
+ --width 20 \
326
+ --height 20
327
+
328
+ # Result: One cached file, infinite reuse, zero overhead
329
+ ```
330
+
331
+ ## Why CSS Classes Beat Inline SVG
332
+
333
+ ### Memory Usage
334
+ - **Inline SVG**: Each icon = new DOM node + XML parsing
335
+ - **CSS Classes**: Each icon = lightweight element + cached background
336
+
337
+ ### Network Efficiency
338
+ - **Inline SVG**: Repeated code on every page load
339
+ - **CSS Classes**: Download once, cached across entire app
340
+
341
+ ### Parsing Performance
342
+ - **Inline SVG**: Browser parses XML structure for each icon
343
+ - **CSS Classes**: Browser applies cached background image
344
+
345
+ ### Maintainability
346
+ - **Inline SVG**: Update icon = find/replace across entire codebase
347
+ - **CSS Classes**: Update icon = regenerate CSS file
348
+
349
+ ## Use Cases
350
+
351
+ ### Icon System Development
352
+ ```bash
353
+ # Create consistent icon set for UI library
354
+ stylicon --input-folder raw-icons/ --out ui-icons/ \
355
+ --fill currentColor \
356
+ --width 20 \
357
+ --height 20 \
358
+ --classes "ui-icon"
359
+ ```
360
+
361
+ ### Theme Variations
362
+ ```bash
363
+ # Generate dark theme icons
364
+ stylicon --input-folder icons/ --out icons-dark/ --fill "#ffffff" --classes "icon dark"
365
+
366
+ # Generate light theme icons
367
+ stylicon --input-folder icons/ --out icons-light/ --fill "#000000" --classes "icon light"
368
+ ```
369
+
370
+ ### Size Variants
371
+ ```bash
372
+ # Small icons (16px)
373
+ stylicon --transform-svg "icons/*.svg" --out icons-sm/ --width 16 --height 16 --classes "icon icon-sm"
374
+
375
+ # Large icons (48px)
376
+ stylicon --transform-svg "icons/*.svg" --out icons-lg/ --width 48 --height 48 --classes "icon icon-lg"
377
+ ```
378
+
379
+ ## Workflow Integration
380
+
381
+ ### Build Process
382
+ ```bash
383
+ #!/bin/bash
384
+ # build-icons.sh
385
+
386
+ # Generate themed icon sets
387
+ stylicon --input-folder src/icons/ --out dist/icons/light/ --fill "#2c3e50" --classes "icon light-theme"
388
+ stylicon --input-folder src/icons/ --out dist/icons/dark/ --fill "#ecf0f1" --classes "icon dark-theme"
389
+
390
+ # Generate size variants
391
+ stylicon --input-folder src/icons/ --out dist/icons/sm/ --width 16 --height 16 --classes "icon icon-sm"
392
+ stylicon --input-folder src/icons/ --out dist/icons/lg/ --width 32 --height 32 --classes "icon icon-lg"
393
+
394
+ echo "Icon generation complete!"
395
+ ```
396
+
397
+ ### Asset Pipeline
398
+ ```bash
399
+ # Process icons during deployment
400
+ stylicon --input-folder assets/raw-icons/ --out public/icons/ \
401
+ --fill currentColor \
402
+ --classes "app-icon" \
403
+ --width 24 \
404
+ --height 24
405
+ ```
406
+
407
+ ## Requirements
408
+
409
+ - Ruby >= 3.1.0
410
+ - Nokogiri gem (for XML processing)
26
411
 
27
412
  ## Development
28
413
 
data/bin/stylicon CHANGED
@@ -1,23 +1,54 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "optparse"
5
+
4
6
  require_relative "../lib/stylicon"
5
7
  require_relative "../lib/stylicon/generator"
6
8
  require_relative "../lib/stylicon/transformer"
9
+ require_relative "../lib/stylicon/batch_transformer"
10
+
11
+ options = {}
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: Stylicon [options]"
14
+
15
+ opts.on("--transform-svg INPUT", "Transform SVG file") { |value| options[:input] = value }
16
+ opts.on("--out OUTPUT", "Output file") { |value| options[:output] = value }
17
+ opts.on("--style STYLE", "CSS Style") { |value| options[:style] = value }
18
+ opts.on("--classes CLASSES", "CSS Classes") { |value| options[:classes] = value }
19
+ opts.on("--fill COLOR", "Fill Color") { |value| options[:fill] = value }
20
+ opts.on("--stroke COLOR", "Stroke Color") { |value| options[:stroke] = value }
21
+ opts.on("--width SIZE", "Width Size") { |value| options[:width] = value }
22
+ opts.on("--height SIZE", "Height Size") { |value| options[:height] = value }
23
+ opts.on("--input-folder FOLDER", "Input Folder for batch processing") { |value| options[:input_folder] = value }
24
+ end.parse!
7
25
 
8
- if ARGV[0] == "--transform-svg"
9
- input = ARGV[1]
10
- out = ARGV[ARGV.index("--out") + 1]
11
- style = ARGV.include?("--style") ? ARGV[ARGV.index("--style") + 1] : nil
12
- classes = ARGV.include?("--classes") ? ARGV[ARGV.index("--classes") + 1] : nil
26
+ if options[:input_folder] || (options[:input] && options[:input].include?("*"))
27
+ input_pattern = options[:input_folder] ? nil : options[:input]
13
28
 
29
+ Stylicon::BatchTransformer.new(
30
+ output_folder: options[:output],
31
+ input_folder: options[:input_folder],
32
+ input_pattern: input_pattern,
33
+ style: options[:style],
34
+ classes: options[:classes],
35
+ fill: options[:fill],
36
+ stroke: options[:stroke],
37
+ width: options[:width],
38
+ height: options[:height]
39
+ ).transform
40
+ exit 0
41
+ elsif options[:input]
14
42
  Stylicon::Transformer.new(
15
- input_svg: input,
16
- output_svg: out,
17
- style: style,
18
- classes: classes
43
+ input_svg: options[:input],
44
+ output_svg: options[:output],
45
+ style: options[:style],
46
+ classes: options[:classes],
47
+ fill: options[:fill],
48
+ stroke: options[:stroke],
49
+ width: options[:width],
50
+ height: options[:height]
19
51
  ).transform
20
-
21
52
  exit 0
22
53
  end
23
54
 
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Stylicon
6
+ # BatchTransformer class to transform folders with svg
7
+ class BatchTransformer
8
+ def initialize(output_folder:, input_pattern: nil, input_folder: nil, **transform_options)
9
+ @input_pattern = input_pattern
10
+ @input_folder = input_folder
11
+ @output_folder = output_folder
12
+ @transform_options = transform_options
13
+ end
14
+
15
+ def transform
16
+ files = find_svg_files
17
+ abort "Error: No SVG files found" if files.empty?
18
+
19
+ begin
20
+ FileUtils.mkdir_p(@output_folder)
21
+ rescue Errno::EACCES
22
+ abort "Error: Permission denied creating directory #{@output_folder}"
23
+ rescue => e
24
+ abort "Error: Failed to create directory #{@output_folder}: #{e.message}"
25
+ end
26
+
27
+ failures = []
28
+
29
+ files.each do |input_file|
30
+ output_file = File.join(@output_folder, File.basename(input_file))
31
+ begin
32
+ Stylicon::Transformer.new(
33
+ input_svg: input_file,
34
+ output_svg: output_file,
35
+ **@transform_options
36
+ ).transform
37
+ rescue => e
38
+ failures << { file: input_file, error: e.message }
39
+ end
40
+ end
41
+
42
+ if failures.any?
43
+ puts "Failed to transform #{failures.length} files:"
44
+ failures.each do |failure|
45
+ puts " #{failure[:file]}: #{failure[:error]}"
46
+ end
47
+ abort "Error: Failed to transform some files"
48
+ end
49
+
50
+ puts "🎨 Transformed #{files.length} SVG files to #{@output_folder} successfully"
51
+ end
52
+
53
+ private
54
+
55
+ def find_svg_files
56
+ if @input_pattern
57
+ Dir.glob(@input_pattern)
58
+ elsif @input_folder
59
+ Dir.glob(File.join(@input_folder, "*.svg"))
60
+ else
61
+ raise ArgumentError, "Must provide an input_pattern or input_folder to select the svg's"
62
+ end
63
+ end
64
+ end
65
+ end
@@ -10,11 +10,22 @@ module Stylicon
10
10
  end
11
11
 
12
12
  def generate
13
- config = YAML.load_file(@config_path)
13
+ begin
14
+ config = YAML.load_file(@config_path)
15
+ rescue Errno::ENOENT
16
+ abort "Error: Config file not found: #{@config_path}"
17
+ rescue Psych::SyntaxError => e
18
+ abort "Error: Config file is not valid YAML: #{@config_path}: #{e.message}"
19
+ end
20
+
21
+ abort "Error: Config file is empty: #{@config_path}" if config.nil? || config.empty?
22
+
14
23
  css = ""
15
24
 
16
25
  config.each do |name, opts|
17
26
  path = opts["path"]
27
+ abort "Error: No path specified for icon #{name} in config" if path.nil? || path.empty?
28
+ abort "Error: SVG file not found: #{path}" unless File.exist?(path)
18
29
  classes = Array(opts["class"] || ".icon-#{name}")
19
30
  background = opts["background"]
20
31
 
@@ -22,6 +33,7 @@ module Stylicon
22
33
  doc = Nokogiri::XML(svg)
23
34
 
24
35
  svg_node = doc.at_css("svg")
36
+ abort "Error: no svg element found in #{path}" if svg_node.nil?
25
37
  svg_node.remove_attribute("fill")
26
38
  svg_node.remove_attribute("width")
27
39
  svg_node.remove_attribute("height")
@@ -43,8 +55,18 @@ module Stylicon
43
55
  RULE
44
56
  end
45
57
 
58
+ begin
46
59
  File.write(@output_path, css)
47
60
  puts "✅ stylicon.css written to #{@output_path}"
61
+ rescue Errno::ENOENT
62
+ abort "Error: output directory does not exist: #{File.dirname(@output_path)}"
63
+ rescue Errno::EACCES
64
+ abort "Error: Permission denied writing to #{@output_path}"
65
+ rescue Errno::ENOSPC
66
+ abort "Error: Not enogh space on device when writing to #{@output_path}"
67
+ rescue => e
68
+ abort "Error: Failed to write output file: #{e.message}"
69
+ end
48
70
  end
49
71
  end
50
72
  end
@@ -14,8 +14,26 @@ module Stylicon
14
14
  end
15
15
 
16
16
  def transform
17
- doc = Nokogiri::XML(File.read(@input_svg))
17
+ begin
18
+ svg_content = File.read(@input_svg)
19
+ rescue Errno::ENOENT
20
+ abort "Error: Input SVG file not found: #{@input_svg}"
21
+ rescue Errno::EACCES
22
+ abort "Error: Permission denied reading file #{@input_svg}"
23
+ rescue Errno::EISDIR
24
+ abort "Error: Path is a directory, not a file: #{@input_svg}"
25
+ rescue => e
26
+ abort "Error: Failed to read input file: #{e.message}"
27
+ end
28
+
29
+ doc = Nokogiri::XML(svg_content)
30
+
31
+ if doc.errors.any?
32
+ abort "Invalid XML in #{@input_svg}: #{doc.errors.first.message}"
33
+ end
34
+
18
35
  svg = doc.at_css("svg")
36
+ abort "Error: No svg element found in #{@input_svg}" if svg.nil?
19
37
 
20
38
  svg["style"] = [svg["style"], @style].compact.join("; ") if @style
21
39
  svg["class"] = [svg["class"], @classes].compact.join(" ") if @classes
@@ -40,7 +58,18 @@ module Stylicon
40
58
  end
41
59
  end
42
60
 
43
- File.write(@output_svg, doc.to_xml)
61
+ begin
62
+ File.write(@output_svg, doc.to_xml)
63
+ rescue Errno::ENOENT
64
+ abort "Error: Output directory does not exist: #{File.dirname(@output_svg)}"
65
+ rescue Errno::EACCES
66
+ abort "Error: Permission denied writing to #{@output_svg}"
67
+ rescue Errno::ENOSPC
68
+ abort "Error: No space left on device when writing #{@output_svg}"
69
+ rescue => e
70
+ abort "Error: Failed to write output file: #{e.message}"
71
+ end
72
+
44
73
  puts "🎨 Transformed SVG written to #{@output_svg}"
45
74
  end
46
75
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stylicon
4
- VERSION = "0.1.5"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/stylicon.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "stylicon/version"
4
+ require_relative "stylicon/generator"
5
+ require_relative "stylicon/transformer"
6
+ require_relative "stylicon/batch_transformer"
4
7
 
5
8
  module Stylicon
6
9
  class Error < StandardError; end
7
- # Your code goes here...
8
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stylicon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - JG
@@ -22,6 +22,7 @@ files:
22
22
  - ".rspec"
23
23
  - ".rubocop.yml"
24
24
  - CHANGELOG.md
25
+ - CLAUDE.md
25
26
  - CODE_OF_CONDUCT.md
26
27
  - LICENSE.txt
27
28
  - README.md
@@ -29,6 +30,7 @@ files:
29
30
  - bin/stylicon
30
31
  - icons.yml
31
32
  - lib/stylicon.rb
33
+ - lib/stylicon/batch_transformer.rb
32
34
  - lib/stylicon/generator.rb
33
35
  - lib/stylicon/transformer.rb
34
36
  - lib/stylicon/version.rb
@@ -56,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
58
  - !ruby/object:Gem::Version
57
59
  version: '0'
58
60
  requirements: []
59
- rubygems_version: 3.7.1
61
+ rubygems_version: 3.6.9
60
62
  specification_version: 4
61
63
  summary: Generate performant CSS classes from SVGs using YAML configuration.
62
64
  test_files: []