Skip to content

Commit 5be1f89

Browse files
committed
feat: support alert icons
1 parent 1822127 commit 5be1f89

File tree

5 files changed

+73
-33
lines changed

5 files changed

+73
-33
lines changed

src/Markdown/Alerts/AlertBlock.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ final class AlertBlock extends AbstractBlock
88
{
99
public function __construct(
1010
public readonly string $alertType,
11+
public readonly ?string $icon,
1112
public readonly ?string $title,
1213
) {
1314
parent::__construct();

src/Markdown/Alerts/AlertBlockParser.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ final class AlertBlockParser implements BlockContinueParserInterface
1515

1616
public function __construct(
1717
protected string $alertType,
18-
protected string $title,
18+
protected ?string $icon,
19+
protected ?string $title,
1920
) {
20-
$this->block = new AlertBlock($alertType, $title);
21+
$this->block = new AlertBlock($alertType, $icon, $title);
2122
}
2223

2324
#[\Override]

src/Markdown/Alerts/AlertBlockRenderer.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use League\CommonMark\Renderer\HtmlRenderer;
88
use League\CommonMark\Renderer\NodeRendererInterface;
99
use League\CommonMark\Util\HtmlElement;
10+
use Tempest\View\Components\Icon;
11+
12+
use function Tempest\get;
1013

1114
final class AlertBlockRenderer implements NodeRendererInterface
1215
{
@@ -21,19 +24,39 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): m
2124
throw new \InvalidArgumentException('Incompatible renderer type: ' . get_class($childRenderer));
2225
}
2326

24-
$cssClass = 'alert alert-' . $node->alertType;
27+
$iconName = match ($node->icon) {
28+
'false' => null,
29+
null => match ($node->alertType) {
30+
'warning' => 'tabler:exclamation-circle',
31+
'info' => 'tabler:info-circle',
32+
'success' => 'tabler:check-circle',
33+
'error' => 'tabler:exclamation-circle',
34+
default => null,
35+
},
36+
default => $node->icon,
37+
};
38+
39+
$icon = $iconName ? get(Icon::class)->render($iconName, class: 'alert-icon') : null;
40+
2541
$content = new HtmlElement(
2642
tagName: 'div',
2743
attributes: ['class' => 'alert-wrapper'],
2844
contents: [
29-
$node->title ? new HtmlElement('span', attributes: ['class' => 'alert-title'], contents: $node->title) : null,
30-
$childRenderer->renderNodes($node->children()),
45+
$icon ? new HtmlElement('div', attributes: ['class' => 'alert-icon-wrapper'], contents: $icon) : null,
46+
new HtmlElement(
47+
tagName: 'div',
48+
attributes: ['class' => 'alert-content'],
49+
contents: [
50+
$node->title ? new HtmlElement('span', attributes: ['class' => 'alert-title'], contents: $node->title) : null,
51+
$childRenderer->renderNodes($node->children()),
52+
],
53+
),
3154
],
3255
);
3356

3457
return new HtmlElement(
3558
'div',
36-
['class' => $cssClass],
59+
['class' => "alert alert-{$node->alertType}"],
3760
$content,
3861
);
3962
}

src/Markdown/Alerts/AlertBlockStartParser.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@ public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserSta
1717
return BlockStart::none();
1818
}
1919

20-
$match = RegexHelper::matchFirst('/^:::(?!group)([a-z]+) ?(.*?)$/i', $cursor->getLine());
20+
$match = RegexHelper::matchFirst('/^:::(?!group)(?<type>[a-z]+)({(?<icon>.*?)})? ?(?<title>.*?)$/i', $cursor->getLine());
2121

2222
if ($match === null) {
2323
return BlockStart::none();
2424
}
2525

2626
$cursor->advanceToEnd();
2727

28-
$alertType = $match[1];
29-
$title = $match[2];
28+
$alertType = $match['type'];
29+
$icon = $match['icon'] ?: null;
30+
$title = $match['title'] ?: null;
3031

31-
return BlockStart::of(new AlertBlockParser($alertType, $title))->at($cursor);
32+
return BlockStart::of(new AlertBlockParser($alertType, $icon, $title))->at($cursor);
3233
}
3334
}

src/Web/assets/typography.css

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,43 @@
2323
}
2424

2525
div.alert-wrapper {
26-
@apply flex flex-col gap-y-2;
26+
@apply flex gap-x-2;
2727

28-
span.alert-title {
29-
@apply text-sm font-semibold inline-block;
28+
.alert-icon-wrapper {
29+
@apply shrink-0;
30+
31+
svg {
32+
@apply size-5;
33+
}
3034
}
3135

32-
p {
33-
@apply my-0 text-sm opacity-90;
36+
.alert-content {
37+
@apply flex flex-col gap-y-2;
38+
39+
.alert-title {
40+
@apply text-sm font-semibold inline-block;
41+
}
42+
43+
p {
44+
@apply my-0 text-sm opacity-90;
45+
}
3446
}
3547
}
3648
}
3749

38-
.code-block {
39-
@apply my-[1.71em] flex flex-col gap-y-0 p-0.5 rounded-lg border border-(--ui-border) bg-(--ui-bg-elevated)/20;
50+
.code-block {
51+
@apply my-[1.71em] flex flex-col gap-y-0 p-0.5 rounded-lg border border-(--ui-border) bg-(--ui-bg-elevated)/20;
4052

41-
&.named-code-block {
42-
.code-block-name {
43-
@apply mb-1.5 mt-1 px-2 font-mono text-(--ui-text-dimmed) text-sm;
44-
}
45-
}
53+
&.named-code-block {
54+
.code-block-name {
55+
@apply mb-1.5 mt-1 px-2 font-mono text-(--ui-text-dimmed) text-sm;
56+
}
57+
}
4658

47-
pre {
48-
@apply my-0;
49-
}
50-
}
59+
pre {
60+
@apply my-0;
61+
}
62+
}
5163

5264
code {
5365
&::before,
@@ -102,16 +114,18 @@
102114
h3 {
103115
@apply text-xl;
104116

105-
a code {
106-
@apply text-xl;
107-
}
117+
a code {
118+
@apply text-xl;
119+
}
108120
}
109121

110-
h4, h5, h6 {
122+
h4,
123+
h5,
124+
h6 {
111125
@apply text-lg;
112126

113-
a code {
114-
@apply text-lg;
115-
}
127+
a code {
128+
@apply text-lg;
129+
}
116130
}
117131
}

0 commit comments

Comments
 (0)