Skip to content

Commit d57e8c2

Browse files
feat: Added Letter Spacing option (#302)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 2349195 commit d57e8c2

File tree

10 files changed

+135
-22
lines changed

10 files changed

+135
-22
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
vendor/
22
.vscode/
3-
.env
3+
.env
4+
.idea

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,22 +120,23 @@ Feel free to [open a PR](https://github.com/DenverCoder1/readme-typing-svg/issue
120120

121121
## 🔧 Options
122122

123-
| Parameter | Details | Type | Example |
124-
| :----------: | :-------------------------------------------------------------------------: | :-----: | :---------------------------------: |
125-
| `lines` | Text to display with lines separated by `;` and `+` for spaces | string | `First+line;Second+line;Third+line` |
126-
| `height` | Height of the output SVG in pixels (default: `50`) | integer | Any positive number |
127-
| `width` | Width of the output SVG in pixels (default: `400`) | integer | Any positive number |
128-
| `size` | Font size in pixels (default: `20`) | integer | Any positive number |
129-
| `font` | Font family (default: `monospace`) | string | Any font from Google Fonts |
130-
| `color` | Color of the text (default: `36BCF7`) | string | Hex code without # (eg. `F724A9`) |
131-
| `background` | Background color of the text (default: `00000000`) | string | Hex code without # (eg. `FEFF4C`) |
132-
| `center` | `true` to center text or `false` for left aligned (default: `false`) | boolean | `true` or `false` |
133-
| `vCenter` | `true` to center vertically or `false`(default) to align above the center | boolean | `true` or `false` |
134-
| `multiline` | `true` to wrap lines or `false` to retype on one line (default: `false`) | boolean | `true` or `false` |
135-
| `duration` | Duration of the printing of a single line in milliseconds (default: `5000`) | integer | Any positive number |
136-
| `pause` | Duration of the pause between lines in milliseconds (default: `0`) | integer | Any non-negative number |
137-
| `repeat` | `true` to loop around to the first line after the last (default: `true`) | boolean | `true` or `false` |
138-
| `separator` | Separator used between lines in the lines parameter (default: `;`) | string | `;`, `;;`, `/`, etc. |
123+
| Parameter | Details | Type | Example |
124+
| :-------------: | :-------------------------------------------------------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------: |
125+
| `lines` | Text to display with lines separated by `;` and `+` for spaces | string | `First+line;Second+line;Third+line` |
126+
| `height` | Height of the output SVG in pixels (default: `50`) | integer | Any positive number |
127+
| `width` | Width of the output SVG in pixels (default: `400`) | integer | Any positive number |
128+
| `size` | Font size in pixels (default: `20`) | integer | Any positive number |
129+
| `font` | Font family (default: `monospace`) | string | Any font from Google Fonts |
130+
| `color` | Color of the text (default: `36BCF7`) | string | Hex code without # (eg. `F724A9`) |
131+
| `background` | Background color of the text (default: `00000000`) | string | Hex code without # (eg. `FEFF4C`) |
132+
| `center` | `true` to center text or `false` for left aligned (default: `false`) | boolean | `true` or `false` |
133+
| `vCenter` | `true` to center vertically or `false`(default) to align above the center | boolean | `true` or `false` |
134+
| `multiline` | `true` to wrap lines or `false` to retype on one line (default: `false`) | boolean | `true` or `false` |
135+
| `duration` | Duration of the printing of a single line in milliseconds (default: `5000`) | integer | Any positive number |
136+
| `pause` | Duration of the pause between lines in milliseconds (default: `0`) | integer | Any non-negative number |
137+
| `repeat` | `true` to loop around to the first line after the last (default: `true`) | boolean | `true` or `false` |
138+
| `separator` | Separator used between lines in the lines parameter (default: `;`) | string | `;`, `;;`, `/`, etc. |
139+
| `letterSpacing` | Letter spacing (default: `normal`) | string | Any css values for the [letter-spacing](https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing) property |
139140

140141
## 📤 Deploying it on your own
141142

src/demo/index.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ function gtag() {
7070
<label for="size">Font size</label>
7171
<input class="param" type="number" id="size" name="size" alt="Font size" placeholder="20" value="20">
7272

73+
<div class="label-group">
74+
<label for="letterSpacing">Letter spacing</label>
75+
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing" target="_blank" class="icon tooltip" title="Enter any css value for the letter-spacing property">
76+
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
77+
<path d="M12 6C9.831 6 8.066 7.765 8.066 9.934h2C10.066 8.867 10.934 8 12 8s1.934.867 1.934 1.934c0 .598-.481 1.032-1.216 1.626-.255.207-.496.404-.691.599C11.029 13.156 11 14.215 11 14.333V15h2l-.001-.633c.001-.016.033-.386.441-.793.15-.15.339-.3.535-.458.779-.631 1.958-1.584 1.958-3.182C15.934 7.765 14.169 6 12 6zM11 16H13V18H11z"></path>
78+
<path d="M12,2C6.486,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.514,2,12,2z M12,20c-4.411,0-8-3.589-8-8s3.589-8,8-8 s8,3.589,8,8S16.411,20,12,20z"></path>
79+
</svg>
80+
</a>
81+
</div>
82+
<input class="param" type="text" id="letterSpacing" name="letterSpacing" alt="Letter spacing" placeholder="normal" value="normal">
83+
7384
<label for="duration">Duration (ms per line)</label>
7485
<input class="param" type="number" id="duration" name="duration" alt="Print duration (ms)" placeholder="5000" value="5000">
7586

src/demo/js/script.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ let preview = {
66
color: "36BCF7",
77
background: "00000000",
88
size: "20",
9+
letterSpacing: "normal",
910
center: "false",
1011
vCenter: "false",
1112
multiline: "false",

src/models/RendererModel.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ class RendererModel
5858
/** @var string $fontCSS CSS required for displaying the selected font */
5959
public $fontCSS;
6060

61+
/** @var string $letterSpacing Letter spacing */
62+
public $letterSpacing;
63+
6164
/** @var string $template Path to template file */
6265
public $template;
6366

@@ -78,6 +81,7 @@ class RendererModel
7881
"repeat" => "true",
7982
"separator" => ";",
8083
"random" => "false",
84+
"letterSpacing" => "normal",
8185
];
8286

8387
/**
@@ -106,6 +110,7 @@ public function __construct($template, $params)
106110
$this->pause = $this->checkNumberNonNegative($params["pause"] ?? $this->DEFAULTS["pause"], "pause");
107111
$this->repeat = $this->checkBoolean($params["repeat"] ?? $this->DEFAULTS["repeat"]);
108112
$this->fontCSS = $this->fetchFontCSS($this->font, $this->weight, $params["lines"]);
113+
$this->letterSpacing = $this->checkLetterSpacing($params["letterSpacing"] ?? $this->DEFAULTS["letterSpacing"]);
109114
}
110115

111116
/**
@@ -224,4 +229,43 @@ private function fetchFontCSS($font, $weight, $text)
224229
// font is not found
225230
return "";
226231
}
232+
233+
/**
234+
* Validate unit for size properties
235+
*
236+
* This method validates if the given unit is a valid CSS size unit.
237+
* It supports various units such as px, em, rem, pt, pc, in, cm, mm,
238+
* ex, ch, vh, vw, vmin, vmax, and percentages.
239+
*
240+
* @param string $unit Unit for validation
241+
* @return bool True if valid, false otherwise
242+
*/
243+
private function isValidUnit($unit)
244+
{
245+
return (bool) preg_match("/^(-?\\d+(\\.\\d+)?(px|em|rem|pt|pc|in|cm|mm|ex|ch|vh|vw|vmin|vmax|%))$/", $unit);
246+
}
247+
248+
/**
249+
* Validate letter spacing
250+
*
251+
* This method validates the letter spacing property for fonts.
252+
* It allows specific keywords (normal, inherit, initial, revert, revert-layer, unset)
253+
* and valid CSS size units.
254+
*
255+
* @param string $letterSpacing Letter spacing for validation
256+
* @return string Validated letter spacing
257+
*/
258+
private function checkLetterSpacing($letterSpacing)
259+
{
260+
// List of valid keywords for letter-spacing
261+
$keywords = "normal|inherit|initial|revert|revert-layer|unset";
262+
263+
// Check if the input matches one of the keywords or a valid unit
264+
if (preg_match("/^($keywords)$/", $letterSpacing) || $this->isValidUnit($letterSpacing)) {
265+
return $letterSpacing;
266+
}
267+
268+
// Return the default letter spacing value if the input is invalid
269+
return $this->DEFAULTS["letterSpacing"];
270+
}
227271
}

src/templates/main.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
</path>
5858
<text font-family='"<?= $font ?>", monospace' fill='<?= $color ?>' font-size='<?= $size ?>'
5959
dominant-baseline='<?= $vCenter ? "middle" : "auto" ?>'
60-
x='<?= $center ? "50%" : "0%" ?>' text-anchor='<?= $center ? "middle" : "start" ?>'>
60+
x='<?= $center ? "50%" : "0%" ?>' text-anchor='<?= $center ? "middle" : "start" ?>'
61+
letter-spacing='<?= $letterSpacing ?>'>
6162
<textPath xlink:href='#path<?= $i ?>'>
6263
<?= $lines[$i] . "\n" ?>
6364
</textPath>

src/views/RendererView.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function render()
4141
"duration" => $this->model->duration,
4242
"pause" => $this->model->pause,
4343
"repeat" => $this->model->repeat,
44+
"letterSpacing" => $this->model->letterSpacing,
4445
]);
4546
// render SVG with output buffering
4647
ob_start();

tests/OptionsTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,33 @@ public function testRandom(): void
367367
$model = new RendererModel("src/templates/main.php", $params);
368368
$this->assertEquals(false, $model->random);
369369
}
370+
371+
/**
372+
* Test Letter Spacing
373+
*/
374+
public function testLetterSpacing(): void
375+
{
376+
// default
377+
$params = [
378+
"lines" => "text",
379+
];
380+
$model = new RendererModel("src/templates/main.php", $params);
381+
$this->assertEquals("normal", $model->letterSpacing);
382+
383+
// invalid
384+
$params = [
385+
"lines" => "text",
386+
"letterSpacing" => "invalid",
387+
];
388+
$model = new RendererModel("src/templates/main.php", $params);
389+
$this->assertEquals("normal", $model->letterSpacing);
390+
391+
// valid
392+
$params = [
393+
"lines" => "text",
394+
"letterSpacing" => "10px",
395+
];
396+
$model = new RendererModel("src/templates/main.php", $params);
397+
$this->assertEquals("10px", $model->letterSpacing);
398+
}
370399
}

tests/RendererTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,24 @@ public function testRandom(): void
326326
$this->assertStringContainsString("> $line </textPath>", $actualSVG);
327327
}
328328
}
329+
330+
/**
331+
* Test Letter Spacing
332+
*/
333+
public function testLetterSpacing()
334+
{
335+
$params = [
336+
"lines" => implode(";", [
337+
"Full-stack web and app developer",
338+
"Self-taught UI/UX Designer",
339+
"10+ years of coding experience",
340+
"Always learning new things",
341+
]),
342+
"letterSpacing" => "10px",
343+
];
344+
$controller = new RendererController($params);
345+
$actualSVG = preg_replace("/\s+/", " ", $controller->render());
346+
$this->assertStringContainsString("letter-spacing='10px'", $actualSVG);
347+
$this->assertStringNotContainsString("letter-spacing='normal'", $actualSVG);
348+
}
329349
}

tests/svg/test_normal.svg

Lines changed: 8 additions & 4 deletions
Loading

0 commit comments

Comments
 (0)