Skip to content

Commit 7cf4f0a

Browse files
authored
Merge pull request #5 from 8fold/favicons
feature: Favicons
2 parents d19d38c + a29d87a commit 7cf4f0a

15 files changed

+326
-51
lines changed

.github/workflows/php8.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
}
1111
],
1212
"require": {
13-
"php": "^8.0",
13+
"php": "^8.1",
1414
"8fold/php-xml-builder": "^1.0"
1515
},
1616
"require-dev": {

composer.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Copyright.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ class Copyright implements Buildable
1313
{
1414
use BuildableImp;
1515

16-
private $useCopyrightSymbol = true;
16+
private bool $useCopyrightSymbol = true;
1717

18-
private $spellOutCopyright = false;
18+
private bool $spellOutCopyright = false;
1919

20-
private $scope = '';
20+
private string $scope = '';
2121

2222
public static function create(
2323
string $holder,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Eightfold\HTMLBuilder\Components;
5+
6+
enum FaviconMetroColors: string
7+
{
8+
case Teal = '#00aba9';
9+
case DarkBlue = '#2b5797';
10+
case LightPurple = '#9f00a7';
11+
case DarkPurple = '#603cba';
12+
case DarkRed = '#b91d47';
13+
case DarkOrange = '#da532c'; // default
14+
case Yellow = '#ffc40d';
15+
case Green = '#00a300';
16+
case Blue = '#2d89ef';
17+
}

src/Components/Favicons.php

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Eightfold\HTMLBuilder\Components;
5+
6+
use Eightfold\XMLBuilder\Contracts\Buildable;
7+
8+
use Eightfold\XMLBuilder\Concatenate;
9+
10+
use Eightfold\XMLBuilder\Implementations\Buildable as BuildableImp;
11+
12+
use Eightfold\HTMLBuilder\Element;
13+
14+
use Eightfold\HTMLBuilder\Components\FaviconMetroColors;
15+
16+
/**
17+
* We use https://realfavicongenerator.net to generate favicon-related assets.
18+
* We presume the names of these assets will not be changed.
19+
*/
20+
class Favicons implements Buildable
21+
{
22+
use BuildableImp;
23+
24+
private string $appName = '';
25+
26+
private bool $metroUsesWhite;
27+
28+
private FaviconMetroColors $metroTileColor = FaviconMetroColors::DarkOrange;
29+
30+
private string $safariThemeColor = '#5bbad5';
31+
32+
public static function create(
33+
string $path = '',
34+
string $themeColor = '#ffffff'
35+
): self {
36+
return new self($path, $themeColor);
37+
}
38+
39+
final private function __construct(
40+
private string $path,
41+
private string $themeColor
42+
) {
43+
}
44+
45+
private function path(): string
46+
{
47+
return $this->path;
48+
}
49+
50+
private function themeColor(): string
51+
{
52+
return $this->themeColor;
53+
}
54+
55+
private function hasPath(): bool
56+
{
57+
return strlen($this->path()) > 0;
58+
}
59+
60+
private function appName(): string
61+
{
62+
return $this->appName;
63+
}
64+
65+
public function withAppName(string $name): self
66+
{
67+
$this->appName = $name;
68+
return $this;
69+
}
70+
71+
private function hasAppName(): bool
72+
{
73+
return strlen($this->appName()) > 0;
74+
}
75+
76+
public function withMetro(
77+
FaviconMetroColors $tileColor = FaviconMetroColors::DarkOrange,
78+
bool $useWhite = false
79+
): self {
80+
$this->metroTileColor = $tileColor;
81+
82+
if ($useWhite !== false) {
83+
$this->metroUsesWhite = $useWhite;
84+
}
85+
86+
return $this;
87+
}
88+
89+
private function hasMetro(): bool
90+
{
91+
if ($this->metroUsesWhite()) {
92+
return true;
93+
}
94+
return false;
95+
}
96+
97+
private function metroUsesWhite(): bool
98+
{
99+
if (isset($this->metroUsesWhite) === false) {
100+
return false;
101+
}
102+
return $this->metroUsesWhite;
103+
}
104+
105+
public function withSafariThemeColor(string $color): self
106+
{
107+
$this->safariThemeColor = $color;
108+
return $this;
109+
}
110+
111+
private function safariThemeColor(): string
112+
{
113+
return $this->safariThemeColor;
114+
}
115+
116+
public function __toString(): string
117+
{
118+
$elements = [
119+
Element::link()->omitEndTag()->props(
120+
'rel apple-touch-icon',
121+
'sizes 180x180',
122+
'href ' . $this->path() . '/apple-touch-icon.png'
123+
),
124+
Element::link()->omitEndTag()->props(
125+
'rel icon',
126+
'type image/png',
127+
'sizes 32x32',
128+
'href ' . $this->path() . '/favicon-32x32.png'
129+
),
130+
Element::link()->omitEndTag()->props(
131+
'rel icon',
132+
'type image/png',
133+
'sizes 16x16',
134+
'href ' . $this->path() . '/favicon-16x16.png'
135+
),
136+
Element::link()->omitEndTag()->props(
137+
'rel manifest',
138+
'href ' . $this->path() . '/site.webmanifest'
139+
),
140+
Element::meta()->omitEndTag()->props(
141+
'name msapplication-TileColor',
142+
'content ' . $this->metroTileColor->value
143+
),
144+
Element::meta()->omitEndTag()->props(
145+
'name theme-color',
146+
'content ' . $this->themeColor()
147+
),
148+
Element::link()->omitEndTag()->props(
149+
'rel mask-icon',
150+
'href ' . $this->path() . '/safari-pinned-tab.svg',
151+
'color ' . $this->safariThemeColor()
152+
)
153+
];
154+
155+
if ($this->hasPath()) {
156+
$elements[] = Element::link()->omitendTag()->props(
157+
'rel shortcut icon',
158+
'href ' . $this->path() . '/favicon.ico'
159+
);
160+
161+
$elements[] = Element::meta()->omitEndTag()->props(
162+
'name msapplication-config',
163+
'content ' . $this->path() . '/browserconfig.xml'
164+
);
165+
}
166+
167+
if ($this->hasMetro() and $this->metroUsesWhite()) {
168+
$elements[] = Element::meta()->omitEndTag()->props(
169+
'name msapplication-TileImage',
170+
'content ' . $this->path() . '/mstile-144x144.png'
171+
);
172+
}
173+
174+
if ($this->hasAppName()) {
175+
$elements[] = Element::meta()->omitEndTag()->props(
176+
'name application-name',
177+
'content ' . $this->appName()
178+
);
179+
180+
$elements[] = Element::meta()->omitEndTag()->props(
181+
'name apple-mobile-web-app-title',
182+
'content ' . $this->appName()
183+
);
184+
}
185+
return (string) Concatenate::create(...$elements);
186+
}
187+
}

src/Document.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
<?php
2-
32
declare(strict_types=1);
43

54
namespace Eightfold\HTMLBuilder;
65

76
use Stringable;
87

9-
use Eightfold\XMLBuilder\Comment;
108
use Eightfold\XMLBuilder\Contracts\Buildable;
9+
use Eightfold\XMLBuilder\Implementations\Buildable as BuildableImp;
10+
1111
use Eightfold\HTMLBuilder\Element;
1212

1313
class Document implements Buildable
1414
{
15+
use BuildableImp;
16+
1517
/**
1618
* @var array<string|Stringable>
1719
*/
@@ -32,8 +34,8 @@ public static function create(
3234

3335
final private function __construct(
3436
private string $title,
35-
private string $lang = 'en',
36-
private string $charset = 'utf-8'
37+
private string $lang,
38+
private string $charset
3739
) {
3840
}
3941

@@ -49,7 +51,7 @@ public function body(string|Stringable ...$content): Document
4951
return $this;
5052
}
5153

52-
public function build(): string
54+
public function __toString(): string
5355
{
5456
$doctype = '<!doctype html>' . "\n";
5557
return $doctype . Element::html(
@@ -62,11 +64,6 @@ public function build(): string
6264
)->props($this->lang())->build();
6365
}
6466

65-
public function __toString(): string
66-
{
67-
return $this->build();
68-
}
69-
7067
private function title(): string
7168
{
7269
return $this->title;

src/Element.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<?php
2-
32
declare(strict_types=1);
43

54
namespace Eightfold\HTMLBuilder;

0 commit comments

Comments
 (0)