Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
vendor/
.vscode/
.env
.env
.idea
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,23 @@ Feel free to [open a PR](https://github.com/DenverCoder1/readme-typing-svg/issue

## 🔧 Options

| Parameter | Details | Type | Example |
| :----------: | :-------------------------------------------------------------------------: | :-----: | :---------------------------------: |
| `lines` | Text to display with lines separated by `;` and `+` for spaces | string | `First+line;Second+line;Third+line` |
| `height` | Height of the output SVG in pixels (default: `50`) | integer | Any positive number |
| `width` | Width of the output SVG in pixels (default: `400`) | integer | Any positive number |
| `size` | Font size in pixels (default: `20`) | integer | Any positive number |
| `font` | Font family (default: `monospace`) | string | Any font from Google Fonts |
| `color` | Color of the text (default: `36BCF7`) | string | Hex code without # (eg. `F724A9`) |
| `background` | Background color of the text (default: `00000000`) | string | Hex code without # (eg. `FEFF4C`) |
| `center` | `true` to center text or `false` for left aligned (default: `false`) | boolean | `true` or `false` |
| `vCenter` | `true` to center vertically or `false`(default) to align above the center | boolean | `true` or `false` |
| `multiline` | `true` to wrap lines or `false` to retype on one line (default: `false`) | boolean | `true` or `false` |
| `duration` | Duration of the printing of a single line in milliseconds (default: `5000`) | integer | Any positive number |
| `pause` | Duration of the pause between lines in milliseconds (default: `0`) | integer | Any non-negative number |
| `repeat` | `true` to loop around to the first line after the last (default: `true`) | boolean | `true` or `false` |
| `separator` | Separator used between lines in the lines parameter (default: `;`) | string | `;`, `;;`, `/`, etc. |
| Parameter | Details | Type | Example |
| :-------------: | :-------------------------------------------------------------------------: | :-----: | :---------------------------------------------------------------------------------------------------------------: |
| `lines` | Text to display with lines separated by `;` and `+` for spaces | string | `First+line;Second+line;Third+line` |
| `height` | Height of the output SVG in pixels (default: `50`) | integer | Any positive number |
| `width` | Width of the output SVG in pixels (default: `400`) | integer | Any positive number |
| `size` | Font size in pixels (default: `20`) | integer | Any positive number |
| `font` | Font family (default: `monospace`) | string | Any font from Google Fonts |
| `color` | Color of the text (default: `36BCF7`) | string | Hex code without # (eg. `F724A9`) |
| `background` | Background color of the text (default: `00000000`) | string | Hex code without # (eg. `FEFF4C`) |
| `center` | `true` to center text or `false` for left aligned (default: `false`) | boolean | `true` or `false` |
| `vCenter` | `true` to center vertically or `false`(default) to align above the center | boolean | `true` or `false` |
| `multiline` | `true` to wrap lines or `false` to retype on one line (default: `false`) | boolean | `true` or `false` |
| `duration` | Duration of the printing of a single line in milliseconds (default: `5000`) | integer | Any positive number |
| `pause` | Duration of the pause between lines in milliseconds (default: `0`) | integer | Any non-negative number |
| `repeat` | `true` to loop around to the first line after the last (default: `true`) | boolean | `true` or `false` |
| `separator` | Separator used between lines in the lines parameter (default: `;`) | string | `;`, `;;`, `/`, etc. |
| `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 |

## 📤 Deploying it on your own

Expand Down
11 changes: 11 additions & 0 deletions src/demo/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ function gtag() {
<label for="size">Font size</label>
<input class="param" type="number" id="size" name="size" alt="Font size" placeholder="20" value="20">

<div class="label-group">
<label for="letterSpacing">Letter spacing</label>
<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">
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<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>
<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>
</svg>
</a>
</div>
<input class="param" type="text" id="letterSpacing" name="letterSpacing" alt="Letter spacing" placeholder="normal" value="normal">

<label for="duration">Duration (ms per line)</label>
<input class="param" type="number" id="duration" name="duration" alt="Print duration (ms)" placeholder="5000" value="5000">

Expand Down
1 change: 1 addition & 0 deletions src/demo/js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ let preview = {
color: "36BCF7",
background: "00000000",
size: "20",
letterSpacing: "normal",
center: "false",
vCenter: "false",
multiline: "false",
Expand Down
44 changes: 44 additions & 0 deletions src/models/RendererModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class RendererModel
/** @var string $fontCSS CSS required for displaying the selected font */
public $fontCSS;

/** @var string $letterSpacing Letter spacing */
public $letterSpacing;

/** @var string $template Path to template file */
public $template;

Expand All @@ -78,6 +81,7 @@ class RendererModel
"repeat" => "true",
"separator" => ";",
"random" => "false",
"letterSpacing" => "normal",
];

/**
Expand Down Expand Up @@ -106,6 +110,7 @@ public function __construct($template, $params)
$this->pause = $this->checkNumberNonNegative($params["pause"] ?? $this->DEFAULTS["pause"], "pause");
$this->repeat = $this->checkBoolean($params["repeat"] ?? $this->DEFAULTS["repeat"]);
$this->fontCSS = $this->fetchFontCSS($this->font, $this->weight, $params["lines"]);
$this->letterSpacing = $this->checkLetterSpacing($params["letterSpacing"] ?? $this->DEFAULTS["letterSpacing"]);
}

/**
Expand Down Expand Up @@ -224,4 +229,43 @@ private function fetchFontCSS($font, $weight, $text)
// font is not found
return "";
}

/**
* Validate unit for size properties
*
* This method validates if the given unit is a valid CSS size unit.
* It supports various units such as px, em, rem, pt, pc, in, cm, mm,
* ex, ch, vh, vw, vmin, vmax, and percentages.
*
* @param string $unit Unit for validation
* @return bool True if valid, false otherwise
*/
private function isValidUnit($unit)
{
return (bool) preg_match("/^(-?\\d+(\\.\\d+)?(px|em|rem|pt|pc|in|cm|mm|ex|ch|vh|vw|vmin|vmax|%))$/", $unit);
}

/**
* Validate letter spacing
*
* This method validates the letter spacing property for fonts.
* It allows specific keywords (normal, inherit, initial, revert, revert-layer, unset)
* and valid CSS size units.
*
* @param string $letterSpacing Letter spacing for validation
* @return string Validated letter spacing
*/
private function checkLetterSpacing($letterSpacing)
{
// List of valid keywords for letter-spacing
$keywords = "normal|inherit|initial|revert|revert-layer|unset";

// Check if the input matches one of the keywords or a valid unit
if (preg_match("/^($keywords)$/", $letterSpacing) || $this->isValidUnit($letterSpacing)) {
return $letterSpacing;
}

// Return the default letter spacing value if the input is invalid
return $this->DEFAULTS["letterSpacing"];
}
}
3 changes: 2 additions & 1 deletion src/templates/main.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
</path>
<text font-family='"<?= $font ?>", monospace' fill='<?= $color ?>' font-size='<?= $size ?>'
dominant-baseline='<?= $vCenter ? "middle" : "auto" ?>'
x='<?= $center ? "50%" : "0%" ?>' text-anchor='<?= $center ? "middle" : "start" ?>'>
x='<?= $center ? "50%" : "0%" ?>' text-anchor='<?= $center ? "middle" : "start" ?>'
letter-spacing='<?= $letterSpacing ?>'>
<textPath xlink:href='#path<?= $i ?>'>
<?= $lines[$i] . "\n" ?>
</textPath>
Expand Down
1 change: 1 addition & 0 deletions src/views/RendererView.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function render()
"duration" => $this->model->duration,
"pause" => $this->model->pause,
"repeat" => $this->model->repeat,
"letterSpacing" => $this->model->letterSpacing,
]);
// render SVG with output buffering
ob_start();
Expand Down
29 changes: 29 additions & 0 deletions tests/OptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,33 @@ public function testRandom(): void
$model = new RendererModel("src/templates/main.php", $params);
$this->assertEquals(false, $model->random);
}

/**
* Test Letter Spacing
*/
public function testLetterSpacing(): void
{
// default
$params = [
"lines" => "text",
];
$model = new RendererModel("src/templates/main.php", $params);
$this->assertEquals("normal", $model->letterSpacing);

// invalid
$params = [
"lines" => "text",
"letterSpacing" => "invalid",
];
$model = new RendererModel("src/templates/main.php", $params);
$this->assertEquals("normal", $model->letterSpacing);

// valid
$params = [
"lines" => "text",
"letterSpacing" => "10px",
];
$model = new RendererModel("src/templates/main.php", $params);
$this->assertEquals("10px", $model->letterSpacing);
}
}
20 changes: 20 additions & 0 deletions tests/RendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,24 @@ public function testRandom(): void
$this->assertStringContainsString("> $line </textPath>", $actualSVG);
}
}

/**
* Test Letter Spacing
*/
public function testLetterSpacing()
{
$params = [
"lines" => implode(";", [
"Full-stack web and app developer",
"Self-taught UI/UX Designer",
"10+ years of coding experience",
"Always learning new things",
]),
"letterSpacing" => "10px",
];
$controller = new RendererController($params);
$actualSVG = preg_replace("/\s+/", " ", $controller->render());
$this->assertStringContainsString("letter-spacing='10px'", $actualSVG);
$this->assertStringNotContainsString("letter-spacing='normal'", $actualSVG);
}
}
12 changes: 8 additions & 4 deletions tests/svg/test_normal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.