From 0d2dcee5eda3d73ea5df99bc4e484fb89fda3528 Mon Sep 17 00:00:00 2001 From: Josh Bruce <15252830+joshbruce@users.noreply.github.com> Date: Sat, 10 Dec 2022 20:18:52 -0500 Subject: [PATCH 1/7] feature: Favicons --- src/Components/FaviconMetroColors.php | 17 ++ src/Components/Favicons.php | 195 ++++++++++++++++++ tests/Components/FaviconsTest.php | 103 +++++++++ tests/Components/favicons-app-name.xml | 1 + tests/Components/favicons-default.xml | 1 + tests/Components/favicons-subfolder.xml | 1 + tests/Components/favicons-theme-color.xml | 1 + .../favicons-windows-metro-tile-color.xml | 1 + tests/Components/favicons-windows-metro.xml | 1 + 9 files changed, 321 insertions(+) create mode 100644 src/Components/FaviconMetroColors.php create mode 100644 src/Components/Favicons.php create mode 100644 tests/Components/FaviconsTest.php create mode 100644 tests/Components/favicons-app-name.xml create mode 100644 tests/Components/favicons-default.xml create mode 100644 tests/Components/favicons-subfolder.xml create mode 100644 tests/Components/favicons-theme-color.xml create mode 100644 tests/Components/favicons-windows-metro-tile-color.xml create mode 100644 tests/Components/favicons-windows-metro.xml diff --git a/src/Components/FaviconMetroColors.php b/src/Components/FaviconMetroColors.php new file mode 100644 index 0000000..9e7f9ef --- /dev/null +++ b/src/Components/FaviconMetroColors.php @@ -0,0 +1,17 @@ + + + + + + + + */ +class Favicons implements Buildable +{ + use BuildableImp; + + private string $appName = ''; + + private bool $metroUsesWhite; + + private FaviconMetroColors $metroTileColor = FaviconMetroColors::DarkOrange; + + private string $safariThemeColor = '#5bbad5'; + + public static function create( + string $path = '', + string $themeColor = '#ffffff' + ): self { + return new self($path, $themeColor); + } + + final private function __construct( + private string $path, + private string $themeColor + ) { + } + + private function path(): string + { + return $this->path; + } + + private function themeColor(): string + { + return $this->themeColor; + } + + private function hasPath(): bool + { + return strlen($this->path()) > 0; + } + + private function appName(): string + { + return $this->appName; + } + + public function withAppName(string $name): self + { + $this->appName = $name; + return $this; + } + + private function hasAppName(): bool + { + return strlen($this->appName()) > 0; + } + + public function withMetro( + FaviconMetroColors $tileColor = FaviconMetroColors::DarkOrange, + bool $useWhite = false + ): self { + $this->metroTileColor = $tileColor; + + if ($useWhite !== false) { + $this->metroUsesWhite = $useWhite; + } + + return $this; + } + + private function hasMetro(): bool + { + if ($this->metroUsesWhite()) { + return true; + } + return false; + } + + private function metroUsesWhite(): bool + { + if (isset($this->metroUsesWhite) === false) { + return false; + } + return $this->metroUsesWhite; + } + + public function withSafariThemeColor(string $color): self + { + $this->safariThemeColor = $color; + return $this; + } + + private function safariThemeColor(): string + { + return $this->safariThemeColor; + } + + public function __toString(): string + { + $elements = [ + Element::link()->omitEndTag()->props( + 'rel apple-touch-icon', + 'sizes 180x180', + 'href ' . $this->path() .'/apple-touch-icon.png' + ), + Element::link()->omitEndTag()->props( + 'rel icon', + 'type image/png', + 'sizes 32x32', + 'href ' . $this->path() .'/favicon-32x32.png' + ), + Element::link()->omitEndTag()->props( + 'rel icon', + 'type image/png', + 'sizes 16x16', + 'href ' . $this->path() .'/favicon-16x16.png' + ), + Element::link()->omitEndTag()->props( + 'rel manifest', + 'href ' . $this->path() . '/site.webmanifest' + ), + Element::meta()->omitEndTag()->props( + 'name msapplication-TileColor', + 'content ' . $this->metroTileColor->value + ), + Element::meta()->omitEndTag()->props( + 'name theme-color', + 'content ' . $this->themeColor() + ), + Element::link()->omitEndTag()->props( + 'rel mask-icon', + 'href ' . $this->path() . '/safari-pinned-tab.svg', + 'color ' . $this->safariThemeColor() + ) + ]; + + if ($this->hasPath()) { + $elements[] = Element::link()->omitendTag()->props( + 'rel shortcut icon', + 'href ' . $this->path() . '/favicon.ico' + ); + + $elements[] = Element::meta()->omitEndTag()->props( + 'name msapplication-config', + 'content ' . $this->path() . '/browserconfig.xml' + ); + } + + if ($this->hasMetro() and $this->metroUsesWhite()) { + $elements[] = Element::meta()->omitEndTag()->props( + 'name msapplication-TileImage', + 'content ' . $this->path() . '/mstile-144x144.png' + ); + } + + if ($this->hasAppName()) { + $elements[] = Element::meta()->omitEndTag()->props( + 'name application-name', + 'content ' . $this->appName() + ); + + $elements[] = Element::meta()->omitEndTag()->props( + 'name apple-mobile-web-app-title', + 'content ' . $this->appName() + ); + } + return (string) Concatenate::create(...$elements); + } +} diff --git a/tests/Components/FaviconsTest.php b/tests/Components/FaviconsTest.php new file mode 100644 index 0000000..ed4358e --- /dev/null +++ b/tests/Components/FaviconsTest.php @@ -0,0 +1,103 @@ +assertSame( + $expected, + $result . "\n" + ); + } + + /** + * @test + */ + public function can_set_theme_color(): void + { + $expected = file_get_contents(__DIR__ . '/favicons-theme-color.xml'); + + $result = (string) Favicons::create( + themeColor: '#000000' + ); + + $this->assertSame( + $expected, + $result . "\n" + ); + } + + /** + * @test + */ + public function can_use_subfolder(): void + { + $expected = file_get_contents(__DIR__ . '/favicons-subfolder.xml'); + + $result = (string) Favicons::create('/subfolder'); + + $this->assertSame( + $expected, + $result . "\n" + ); + } + + /** + * @test + */ + public function can_use_custom_app_name(): void + { + $expected = file_get_contents(__DIR__ . '/favicons-app-name.xml'); + + $result = (string) Favicons::create()->withAppName('Override page title'); + + $this->assertSame( + $expected, + $result . "\n" + ); + } + + /** + * @test + */ + public function can_use_windows_metro_settings(): void + { + $expected = file_get_contents(__DIR__ . '/favicons-windows-metro.xml'); + + $result = (string) Favicons::create()->withMetro(useWhite: true); + + $this->assertSame( + $expected, + $result . "\n" + ); + + $expected = file_get_contents( + __DIR__ . '/favicons-windows-metro-tile-color.xml' + ); + + $result = (string) Favicons::create()->withMetro( + FaviconMetroColors::Teal + ); + + $this->assertSame( + $expected, + $result . "\n" + ); + } +} diff --git a/tests/Components/favicons-app-name.xml b/tests/Components/favicons-app-name.xml new file mode 100644 index 0000000..dc255e6 --- /dev/null +++ b/tests/Components/favicons-app-name.xml @@ -0,0 +1 @@ + diff --git a/tests/Components/favicons-default.xml b/tests/Components/favicons-default.xml new file mode 100644 index 0000000..5438971 --- /dev/null +++ b/tests/Components/favicons-default.xml @@ -0,0 +1 @@ + diff --git a/tests/Components/favicons-subfolder.xml b/tests/Components/favicons-subfolder.xml new file mode 100644 index 0000000..9e6ef2e --- /dev/null +++ b/tests/Components/favicons-subfolder.xml @@ -0,0 +1 @@ + diff --git a/tests/Components/favicons-theme-color.xml b/tests/Components/favicons-theme-color.xml new file mode 100644 index 0000000..2ed005c --- /dev/null +++ b/tests/Components/favicons-theme-color.xml @@ -0,0 +1 @@ + diff --git a/tests/Components/favicons-windows-metro-tile-color.xml b/tests/Components/favicons-windows-metro-tile-color.xml new file mode 100644 index 0000000..1b58af6 --- /dev/null +++ b/tests/Components/favicons-windows-metro-tile-color.xml @@ -0,0 +1 @@ + diff --git a/tests/Components/favicons-windows-metro.xml b/tests/Components/favicons-windows-metro.xml new file mode 100644 index 0000000..7b28d74 --- /dev/null +++ b/tests/Components/favicons-windows-metro.xml @@ -0,0 +1 @@ + From bd074a71bfe2d2908ce6312dd6e364af2f258992 Mon Sep 17 00:00:00 2001 From: Josh Bruce <15252830+joshbruce@users.noreply.github.com> Date: Sat, 10 Dec 2022 20:22:55 -0500 Subject: [PATCH 2/7] fix: Styles and Stan --- src/Components/Copyright.php | 6 +++--- src/Components/Favicons.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Components/Copyright.php b/src/Components/Copyright.php index 7c13ca9..55f38a1 100644 --- a/src/Components/Copyright.php +++ b/src/Components/Copyright.php @@ -13,11 +13,11 @@ class Copyright implements Buildable { use BuildableImp; - private $useCopyrightSymbol = true; + private bool $useCopyrightSymbol = true; - private $spellOutCopyright = false; + private bool $spellOutCopyright = false; - private $scope = ''; + private string $scope = ''; public static function create( string $holder, diff --git a/src/Components/Favicons.php b/src/Components/Favicons.php index 7d50eca..85e5197 100644 --- a/src/Components/Favicons.php +++ b/src/Components/Favicons.php @@ -127,19 +127,19 @@ public function __toString(): string Element::link()->omitEndTag()->props( 'rel apple-touch-icon', 'sizes 180x180', - 'href ' . $this->path() .'/apple-touch-icon.png' + 'href ' . $this->path() . '/apple-touch-icon.png' ), Element::link()->omitEndTag()->props( 'rel icon', 'type image/png', 'sizes 32x32', - 'href ' . $this->path() .'/favicon-32x32.png' + 'href ' . $this->path() . '/favicon-32x32.png' ), Element::link()->omitEndTag()->props( 'rel icon', 'type image/png', 'sizes 16x16', - 'href ' . $this->path() .'/favicon-16x16.png' + 'href ' . $this->path() . '/favicon-16x16.png' ), Element::link()->omitEndTag()->props( 'rel manifest', From 8ccc71796f22d6e6f51d5e7ea28f59b767fb1f10 Mon Sep 17 00:00:00 2001 From: Josh Bruce <15252830+joshbruce@users.noreply.github.com> Date: Sat, 10 Dec 2022 20:24:34 -0500 Subject: [PATCH 3/7] BC: PHP 8.1+ required --- .github/workflows/php8.yml | 34 ---------------------------------- composer.json | 2 +- 2 files changed, 1 insertion(+), 35 deletions(-) delete mode 100644 .github/workflows/php8.yml diff --git a/.github/workflows/php8.yml b/.github/workflows/php8.yml deleted file mode 100644 index cd55c28..0000000 --- a/.github/workflows/php8.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: PHP 8.0 - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP Action - uses: shivammathur/setup-php@2.15.0 - with: - php-version: '8.0' - - - name: Validate composer.json and composer.lock - run: composer validate - - - name: Install dependencies - run: composer install --prefer-dist --no-progress - - - name: Run style check - run: composer run style - - - name: Run static analyzer - run: composer run stan - - - name: Run tests - run: composer run test diff --git a/composer.json b/composer.json index 5ec7ecf..9de95b6 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": "^8.0", + "php": "^8.1", "8fold/php-xml-builder": "^1.0" }, "require-dev": { From 21b235b9f6412be0c3ea94281bc00031aa9bbc3b Mon Sep 17 00:00:00 2001 From: Josh Bruce <15252830+joshbruce@users.noreply.github.com> Date: Sat, 10 Dec 2022 20:25:37 -0500 Subject: [PATCH 4/7] update: Composer lock --- composer.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.lock b/composer.lock index 150766d..25f7820 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "199aa517e28afc812147d2db276ef5b7", + "content-hash": "c947d8e6a9d83a5901fde433b192b1d2", "packages": [ { "name": "8fold/php-xml-builder", @@ -1915,7 +1915,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^8.0" + "php": "^8.1" }, "platform-dev": [], "plugin-api-version": "2.3.0" From 67ea899605e4379af2e1ff9a304c45f38b4fc238 Mon Sep 17 00:00:00 2001 From: Josh Bruce <15252830+joshbruce@users.noreply.github.com> Date: Sat, 10 Dec 2022 20:31:06 -0500 Subject: [PATCH 5/7] remove: Commented code --- src/Components/Favicons.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Components/Favicons.php b/src/Components/Favicons.php index 85e5197..b303da1 100644 --- a/src/Components/Favicons.php +++ b/src/Components/Favicons.php @@ -16,14 +16,6 @@ /** * We use https://realfavicongenerator.net to generate favicon-related assets. * We presume the names of these assets will not be changed. - - - - - - - - */ class Favicons implements Buildable { From 40322edf84bccf3d1bfd479cce858d5fad2dde13 Mon Sep 17 00:00:00 2001 From: Josh Bruce <15252830+joshbruce@users.noreply.github.com> Date: Sat, 10 Dec 2022 20:31:17 -0500 Subject: [PATCH 6/7] remove: Whitespace --- src/Element.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Element.php b/src/Element.php index 2a9cfce..0e8298c 100644 --- a/src/Element.php +++ b/src/Element.php @@ -1,5 +1,4 @@ Date: Sat, 10 Dec 2022 20:32:27 -0500 Subject: [PATCH 7/7] update: To use implementations, unneeded defaults --- src/Document.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Document.php b/src/Document.php index 97c4751..7402b4d 100644 --- a/src/Document.php +++ b/src/Document.php @@ -1,17 +1,19 @@ */ @@ -32,8 +34,8 @@ public static function create( final private function __construct( private string $title, - private string $lang = 'en', - private string $charset = 'utf-8' + private string $lang, + private string $charset ) { } @@ -49,7 +51,7 @@ public function body(string|Stringable ...$content): Document return $this; } - public function build(): string + public function __toString(): string { $doctype = '' . "\n"; return $doctype . Element::html( @@ -62,11 +64,6 @@ public function build(): string )->props($this->lang())->build(); } - public function __toString(): string - { - return $this->build(); - } - private function title(): string { return $this->title;