Skip to content

Commit db26b60

Browse files
committed
Add support for injecting "unsafe" HTML into places that currently take strings as an escape hatch a-la dangerouslySetInnerHTML. Use it to highlight code elements in hero page.
1 parent 072c4e4 commit db26b60

5 files changed

Lines changed: 44 additions & 13 deletions

File tree

include/branch-highlights.inc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ return [
99
],
1010
[
1111
'title' => 'Pipe Operator',
12-
'about' => 'The |> operator enables chaining callables left-to-right, passing values smoothly through multiple functions without intermediary variables.',
12+
'about' => 'The `|>` operator enables chaining callables left-to-right, passing values smoothly through multiple functions without intermediary variables.',
1313
],
1414
[
1515
'title' => 'Clone With',
16-
'about' => 'Clone objects and update properties with the new clone() syntax, making the "with-er" pattern simple for readonly classes.',
16+
'about' => 'Clone objects and update properties with the new `clone()` syntax, making the "with-er" pattern simple for readonly classes.',
1717
],
1818
[
19-
'title' => '#[\NoDiscard] Attribute',
20-
'about' => 'The #[\NoDiscard] attribute warns when a return value isn’t used, helping prevent mistakes and improving overall API safety.',
19+
'title' => '`#[\NoDiscard]` Attribute',
20+
'about' => 'The `#[\NoDiscard]` attribute warns when a return value isn’t used, helping prevent mistakes and improving overall API safety.',
2121
],
2222
[
2323
'title' => 'Closures and First-Class Callables in Constant Expressions',
@@ -42,7 +42,7 @@ return [
4242
],
4343
[
4444
'title' => '#[Deprecated] Attribute',
45-
'short' => '#[Deprecated] attribute signals removal intent',
45+
'short' => '`#[Deprecated]` attribute signals removal intent',
4646
],
4747
[
4848
'title' => 'Additional Array Functions',
@@ -84,7 +84,7 @@ return [
8484
],
8585
[
8686
'title' => 'Improved Standalone Types',
87-
'short' => 'Null, true and false are now usable as types',
87+
'short' => '`Null`, `true` and `false` are now usable as types',
8888
],
8989
],
9090
],

public/index.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use phpweb\Releases\Branches;
55
use phpweb\Releases\VersionLogos;
66
use phpweb\Themes\ClickableCard;
7+
use phpweb\Themes\HTML;
78
use phpweb\Themes\ThemeRenderer;
89

910
require_once __DIR__ . '/../include/prepend.inc';
@@ -205,7 +206,6 @@ public function render(): void
205206
</div>
206207
</div>
207208
<?php
208-
// echo $this->theme->clickableCards(self::getHeaderCards(), id: 'header-cards');
209209
});
210210

211211
$this->drawSection('primary', 'releases', function() use ($latestRelease, $latestReleases) {
@@ -328,8 +328,12 @@ public function render(): void
328328
}
329329

330330

331-
private function safe(string $content): string
331+
private function safe(string|HTML $content): string
332332
{
333+
if ($content instanceof HTML) {
334+
return $content->html;
335+
}
336+
333337
return htmlspecialchars($content, ENT_QUOTES);
334338
}
335339

@@ -361,8 +365,12 @@ private function drawLatestVersionHeader(array $release): void
361365
<div class="lp-lhr-highlights">
362366
<?php foreach ($highlights as $highlight) { ?>
363367
<div class="lp-lrh-highlight">
364-
<div class="lp-lrh-highlight-title"><?= $this->safe($highlight['title']) ?></div>
365-
<div class="lp-lrh-highlight-text"><?= $this->safe($highlight['about'] ?? $highlight['short'] ?? '') ?></div>
368+
<div class="lp-lrh-highlight-title">
369+
<?= $this->safe($this->theme->textWithCode($highlight['title'])) ?>
370+
</div>
371+
<div class="lp-lrh-highlight-text">
372+
<?= $this->safe($this->theme->textWithCode($highlight['about'] ?? $highlight['short'] ?? '')) ?>
373+
</div>
366374
</div>
367375
<?php } ?>
368376
</div>

src/Themes/ClickableCard.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
class ClickableCard
66
{
77
public function __construct(
8-
public string $title,
8+
public string|HTML $title,
99
public string $href,
1010
public string $href_label = '',
1111
public string $image = '',
12-
public string $body = '',
12+
public string|HTML $body = '',
1313
) {
1414
}
1515
}

src/Themes/HTML.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace phpweb\Themes;
4+
5+
readonly class HTML
6+
{
7+
public function __construct(public string $html)
8+
{
9+
}
10+
}

src/Themes/ThemeRenderer.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace phpweb\Themes;
44

55
use phpweb\Utils;
6+
use function preg_replace;
67

78
class ThemeRenderer
89
{
@@ -76,8 +77,20 @@ public function sectionHeader(string $title, string $subtitle = ''): string
7677
});
7778
}
7879

79-
private function safe(string|int|float $value): string
80+
private function safe(string|int|float|HTML $value): string
8081
{
82+
if ($value instanceof HTML) {
83+
return $value->html;
84+
}
85+
8186
return htmlspecialchars((string)$value);
8287
}
88+
89+
public function textWithCode(string $input): HTML
90+
{
91+
$html = preg_replace('/`(.+?)`/i', '<code>$1</code>', htmlspecialchars($input));
92+
assert(is_string($html));
93+
94+
return new HTML($html);
95+
}
8396
}

0 commit comments

Comments
 (0)