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 +4 -4
- data/CLAUDE.md +28 -0
- data/README.md +394 -9
- data/bin/stylicon +41 -10
- data/lib/stylicon/batch_transformer.rb +65 -0
- data/lib/stylicon/generator.rb +23 -1
- data/lib/stylicon/transformer.rb +31 -2
- data/lib/stylicon/version.rb +1 -1
- data/lib/stylicon.rb +3 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 38690808a8ba07f5bfb35310eee321d2f2eaec78799384847d756ba6661800cc
|
|
4
|
+
data.tar.gz: c438a87c7cc767734786e4694b50d0384e938447f0fa53c5c039f6febcad4e2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
5
|
+
## Performance First.
|
|
6
6
|
|
|
7
|
-
|
|
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
|
-
|
|
33
|
+
### Results
|
|
10
34
|
|
|
11
|
-
|
|
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
|
-
|
|
73
|
+
gem install stylicon
|
|
15
74
|
```
|
|
16
75
|
|
|
17
|
-
|
|
76
|
+
Or add it to your Gemfile:
|
|
18
77
|
|
|
19
78
|
```bash
|
|
20
|
-
|
|
79
|
+
bundle add stylicon
|
|
21
80
|
```
|
|
22
81
|
|
|
23
82
|
## Usage
|
|
24
83
|
|
|
25
|
-
|
|
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
|
|
9
|
-
|
|
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:
|
|
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
|
data/lib/stylicon/generator.rb
CHANGED
|
@@ -10,11 +10,22 @@ module Stylicon
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def generate
|
|
13
|
-
|
|
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
|
data/lib/stylicon/transformer.rb
CHANGED
|
@@ -14,8 +14,26 @@ module Stylicon
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def transform
|
|
17
|
-
|
|
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
|
-
|
|
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
|
data/lib/stylicon/version.rb
CHANGED
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
|
|
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.
|
|
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: []
|