diff --git a/README.md b/README.md
index 74972d0c..9e372d12 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,7 @@ Feel free to [open a PR](https://github.com/DenverCoder1/readme-typing-svg/issue
| `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` |
## 📤 Deploying it on your own
diff --git a/src/demo/index.php b/src/demo/index.php
index d050fb21..c4db5218 100644
--- a/src/demo/index.php
+++ b/src/demo/index.php
@@ -83,23 +83,29 @@ function gtag() {
Horizontally Centered
-
+
false
true
Vertically Centered
-
+
false
true
Multiline
-
+
Type sentences on one line
Each sentence on a new line
+ Repeat
+
+ true
+ false
+
+
Width ✕ Height
diff --git a/src/demo/js/script.js b/src/demo/js/script.js
index e865e6a2..d6a87cd0 100644
--- a/src/demo/js/script.js
+++ b/src/demo/js/script.js
@@ -13,6 +13,7 @@ let preview = {
height: "50",
duration: "5000",
pause: "0",
+ repeat: "true",
},
dummyText: [
"The five boxing wizards jump quickly",
diff --git a/src/models/RendererModel.php b/src/models/RendererModel.php
index 0681ac57..60746bde 100644
--- a/src/models/RendererModel.php
+++ b/src/models/RendererModel.php
@@ -46,6 +46,9 @@ class RendererModel
/** @var int $pause pause duration between lines in milliseconds */
public $pause;
+ /** @var bool $repeat Whether to loop around to the first line after the last */
+ public $repeat;
+
/** @var string $fontCSS CSS required for displaying the selected font */
public $fontCSS;
@@ -66,6 +69,7 @@ class RendererModel
"multiline" => "false",
"duration" => "5000",
"pause" => "0",
+ "repeat" => "true",
];
/**
@@ -90,6 +94,7 @@ public function __construct($template, $params)
$this->multiline = $this->checkBoolean($params["multiline"] ?? $this->DEFAULTS["multiline"]);
$this->duration = $this->checkNumberPositive($params["duration"] ?? $this->DEFAULTS["duration"], "duration");
$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"]);
}
diff --git a/src/templates/main.php b/src/templates/main.php
index 31cf11d4..7664f89b 100644
--- a/src/templates/main.php
+++ b/src/templates/main.php
@@ -5,43 +5,62 @@
style='background-color: = $background ?>;'
width='= $width ?>px' height='= $height ?>px'>
- = preg_replace("/\n/", "\n\t", $fontCSS) ?>
+ = $fontCSS ?>
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
- dominant-baseline='middle'
-
- dominant-baseline='auto'
-
-
- x='50%' text-anchor='middle'>
-
- x='0%' text-anchor='start'>
-
+ dominant-baseline='= $vCenter ? "middle" : "auto" ?>'
+ x='= $center ? "50%" : "0%" ?>' text-anchor='= $center ? "middle" : "start" ?>'>
= $lines[$i] . "\n" ?>
-
-
diff --git a/src/views/RendererView.php b/src/views/RendererView.php
index 1e98b245..7c540003 100644
--- a/src/views/RendererView.php
+++ b/src/views/RendererView.php
@@ -40,6 +40,7 @@ public function render()
"fontCSS" => $this->model->fontCSS,
"duration" => $this->model->duration,
"pause" => $this->model->pause,
+ "repeat" => $this->model->repeat,
]);
// render SVG with output buffering
ob_start();
diff --git a/tests/OptionsTest.php b/tests/OptionsTest.php
index b11e997d..4e536127 100644
--- a/tests/OptionsTest.php
+++ b/tests/OptionsTest.php
@@ -287,4 +287,33 @@ public function testInvalidPause(): void
];
print_r(new RendererModel("src/templates/main.php", $params));
}
+
+ /**
+ * Test repeat set to true, false, other
+ */
+ public function testRepeat(): void
+ {
+ // not set
+ $params = [
+ "lines" => "text",
+ ];
+ $model = new RendererModel("src/templates/main.php", $params);
+ $this->assertEquals(true, $model->repeat);
+
+ // true
+ $params = [
+ "lines" => "text",
+ "repeat" => "true",
+ ];
+ $model = new RendererModel("src/templates/main.php", $params);
+ $this->assertEquals(true, $model->repeat);
+
+ // other / false
+ $params = [
+ "lines" => "text",
+ "repeat" => "other",
+ ];
+ $model = new RendererModel("src/templates/main.php", $params);
+ $this->assertEquals(false, $model->repeat);
+ }
}
diff --git a/tests/RendererTest.php b/tests/RendererTest.php
index 54d678e4..160404f3 100644
--- a/tests/RendererTest.php
+++ b/tests/RendererTest.php
@@ -8,6 +8,24 @@
final class RendererTest extends TestCase
{
+ /**
+ * Static method to assert strings are equal while ignoring whitespace
+ *
+ * @param string $expected
+ * @param string $actual
+ */
+ public static function compareNoCommentsOrWhitespace(string $expected, string $actual)
+ {
+ // remove comments and whitespace
+ $expected = preg_replace("/\s+/", " ", preg_replace("//s", " ", $expected));
+ $actual = preg_replace("/\s+/", " ", preg_replace("//s", " ", $actual));
+ // add newlines to make it easier to debug
+ $expected = str_replace(">", ">\n", $expected);
+ $actual = str_replace(">", ">\n", $actual);
+ // assert strings are equal
+ self::assertSame($expected, $actual);
+ }
+
/**
* Test normal card render
*/
@@ -26,7 +44,9 @@ public function testCardRender(): void
"height" => "50",
];
$controller = new RendererController($params);
- $this->assertStringEqualsFile("tests/svg/test_normal.svg", $controller->render());
+ $expectedSVG = file_get_contents("tests/svg/test_normal.svg");
+ $actualSVG = $controller->render();
+ $this->compareNoCommentsOrWhitespace($expectedSVG, $actualSVG);
}
public function testMultilineCardRender(): void
@@ -134,7 +154,9 @@ public function testLineTrimming(): void
"height" => "50",
];
$controller = new RendererController($params);
- $this->assertStringEqualsFile("tests/svg/test_normal.svg", $controller->render());
+ $expectedSVG = file_get_contents("tests/svg/test_normal.svg");
+ $actualSVG = $controller->render();
+ $this->compareNoCommentsOrWhitespace($expectedSVG, $actualSVG);
}
/**
@@ -205,4 +227,57 @@ public function testPauseMultiline(): void
$this->assertStringContainsString("dur='12000ms'", $controller->render());
$this->assertStringContainsString("keyTimes='0;0.5;0.91666666666667;1'", $controller->render());
}
+
+ /**
+ * Test repeat set to false
+ */
+ public function testRepeatFalse(): void
+ {
+ $params = [
+ "lines" => implode(";", [
+ "Full-stack web and app developer",
+ "Self-taught UI/UX Designer",
+ "10+ years of coding experience",
+ "Always learning new things",
+ ]),
+ "center" => "true",
+ "vCenter" => "true",
+ "width" => "380",
+ "height" => "50",
+ "repeat" => "false",
+ ];
+ $controller = new RendererController($params);
+ $actualSVG = preg_replace("/\s+/", " ", $controller->render());
+ $this->assertStringContainsString("begin='0s'", $actualSVG);
+ $this->assertStringContainsString(
+ "begin='d2.end' dur='5000ms' fill='freeze' values='m0,25 h0 ; m0,25 h380 ; m0,25 h380 ; m0,25 h380'",
+ $actualSVG
+ );
+ $this->assertStringNotContainsString(";d3.end", $actualSVG);
+ }
+
+ /**
+ * Test repeat set to false on multiline card
+ */
+ public function testRepeatFalseMultiline(): void
+ {
+ $params = [
+ "lines" => implode(";", [
+ "Full-stack web and app developer",
+ "Self-taught UI/UX Designer",
+ "10+ years of coding experience",
+ "Always learning new things",
+ ]),
+ "center" => "true",
+ "vCenter" => "true",
+ "width" => "380",
+ "height" => "200",
+ "multiline" => "true",
+ "repeat" => "false",
+ ];
+ $controller = new RendererController($params);
+ $actualSVG = preg_replace("/\s+/", " ", $controller->render());
+ $this->assertStringContainsString("begin='0s'", $actualSVG);
+ $this->assertStringNotContainsString(";d3.end", $actualSVG);
+ }
}
diff --git a/tests/svg/test_normal.svg b/tests/svg/test_normal.svg
index ad69e4f5..7c7b70f3 100644
--- a/tests/svg/test_normal.svg
+++ b/tests/svg/test_normal.svg
@@ -5,9 +5,9 @@
style='background-color: #00000000;'
width='380px' height='50px'>
-
-
@@ -20,7 +20,8 @@
-
@@ -33,7 +34,8 @@
-
@@ -46,7 +48,8 @@
-