Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion docs/1-essentials/02-views.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,10 +554,58 @@ Includes the CSRF token in a form

### `x-icon`

This component provides the ability to inject any icon from the [Iconify](https://iconify.design/) project in your templates.
This component provides the ability to inject any icon from the [Iconify](https://iconify.design/) project in your templates. By default, the Iconify API returns width and height dimensions of 1em, so that the icon will scale with text-size, or with Tailwind text-size utility classes, if you choose to use those.

```html
<x-icon name="material-symbols:php" class="size-4 text-indigo-400" />

<svg class="size-4 text-indigo-400" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentcolor"
d="m3 15v9h3.5q.6 0 1.05.45t8 10.5v1q0 .6-.45 1.05t6.5 13h-2v2zm6.5 0v9h11v2h2v9h1.5v6h13v-2.5h-2v15zm7 0v9h20q.6 0 1.05.45t.45 1.05v1q0 .6-.45 1.05t20 13h-2v2zm-12-3.5h2v-1h-2zm13.5 0h2v-1h-2z"
/>
</svg>
```

This behaviour can be overridden in a couple of ways to suit your needs.

Firstly, you can disable the width and height attributes entirely, by setting the `noSize` prop, and then provide dimensions using Tailwind w- and -h utilities, or your own custom class.

```html
<x-icon name="material-symbols:php" noSize class="w-[24px] h-[24px] text-indigo-400" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be no-size

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there are reason we'd ever want the default without no-size? We already control the icon component, right? Couldn't we always use no-size underneath, and then just set the default size in the icon component, which could then be overwritten?


<svg class="w-[24px] h-[24px] text-indigo-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the generated output, right? Add a comment so that that's clear:

<path
fill="currentcolor"
d="m3 15v9h3.5q.6 0 1.05.45t8 10.5v1q0 .6-.45 1.05t6.5 13h-2v2zm6.5 0v9h11v2h2v9h1.5v6h13v-2.5h-2v15zm7 0v9h20q.6 0 1.05.45t.45 1.05v1q0 .6-.45 1.05t20 13h-2v2zm-12-3.5h2v-1h-2zm13.5 0h2v-1h-2z"
/>
</svg>
```

Secondly, if you aren't using Tailwind, or wish to set for a single icon without making a class, you can instead pass dimensions via the `style` prop.

```html
<x-icon name="material-symbols:php" noSize style="width: 24px; height: 24px;" />

<svg style="width: 24px; height: 24px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
fill="currentcolor"
d="m3 15v9h3.5q.6 0 1.05.45t8 10.5v1q0 .6-.45 1.05t6.5 13h-2v2zm6.5 0v9h11v2h2v9h1.5v6h13v-2.5h-2v15zm7 0v9h20q.6 0 1.05.45t.45 1.05v1q0 .6-.45 1.05t20 13h-2v2zm-12-3.5h2v-1h-2zm13.5 0h2v-1h-2z"
/>
</svg>
```

Finally, you may override the width and height properties directly with the props `width` and `height`. You must set both, to assign dimensions in this way.

```html
<x-icon name="material-symbols:php" width="24px" height="24px" />

<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24">
<path
fill="currentcolor"
d="m3 15v9h3.5q.6 0 1.05.45t8 10.5v1q0 .6-.45 1.05t6.5 13h-2v2zm6.5 0v9h11v2h2v9h1.5v6h13v-2.5h-2v15zm7 0v9h20q.6 0 1.05.45t.45 1.05v1q0 .6-.45 1.05t20 13h-2v2zm-12-3.5h2v-1h-2zm13.5 0h2v-1h-2z"
/>
</svg>
```

The first time a specific icon is being rendered, Tempest will query the [Iconify API](https://iconify.design/docs/api/queries.html) to fetch the corresponding SVG tag. The result of this query will be cached indefinitely, so it can be reused at no further cost.
Expand Down
67 changes: 49 additions & 18 deletions packages/view/src/Components/x-icon.view.php
Original file line number Diff line number Diff line change
@@ -1,37 +1,68 @@
<?php
/**
* @var string $name
* SEE: docs/1-essentials/02-views.md for usage instructions
* @var string|null $name
* @var string|null $class
* @var string|null $style
* @var string|null $width
* @var string|null $height
* @var bool|null $noSize
*/

use Tempest\Core\Environment;
use Tempest\Icon\Icon;
use Tempest\Support\Str\ImmutableString;

use function Tempest\Container\get;
use function Tempest\Support\str;

$class ??= null;
$name ??= null;
$environment = get(Environment::class);

if ($name) {
$svg = get(Icon::class)->render($name);
} else {
$svg = null;
}

if ($svg === null && $environment->isLocal()) {
$svg = '<!-- unknown-icon: ' . $name . ' -->';
}

if ($class) {
$svg = str($svg)
->replace(
$svg = str(is_string($name) ? get(Icon::class)->render($name) : null)
->when(
fn (ImmutableString $s): bool => $s->toString() === '' && $environment->isLocal(),
fn (ImmutableString $s): ImmutableString => str("<!-- unknown-icon: {$name} -->"),
)
->when(
$style ?? null,
fn (ImmutableString $s): ImmutableString => $s->replace(
search: '<svg',
replace: "<svg style=\"{$style}\"",
),
)
->when(
$class ?? null,
fn (ImmutableString $s): ImmutableString => $s->replace(
search: '<svg',
replace: "<svg class=\"{$class}\"",
)
->toString();
}
),
)
->when(
isset($noSize) && ($noSize === '' || $noSize === true),
fn (ImmutableString $s): ImmutableString => $s
->replace(
search: ' width="1em"',
replace: '',
)
->replace(
search: ' height="1em"',
replace: '',
),
)
->when(
isset($width, $height) && ! ($noSize ?? false),
fn (ImmutableString $s): ImmutableString => $s
->replace(
search: ' width="1em"',
replace: " width=\"{$width}\"",
)
->replace(
search: ' height="1em"',
replace: " height=\"{$height}\"",
),
)
->toString();
?>

{!! $svg !!}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<x-test-layout>
<x-slot name="icon">
<x-icon name="ph:eye" class="size-5" />
<x-icon name="material-symbols:php" class="size-5" />
</x-slot>
Test
</x-test-layout>
Loading