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
66 changes: 66 additions & 0 deletions asset/css/callout.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Layout
.callout {
display: flex;
justify-content: center;
column-gap: 1em;

width: fit-content;
margin: 0 auto 1em;

&.callout-fullwidth {
width: 100%;
justify-content: start;
}

&.form-callout {
margin-left: 14em;
width: auto;
justify-content: start;
}

i.icon::before {
margin-right: 0;
}

p {
margin: 0;
}

.callout-title {
margin-bottom: .5em;
}

.callout-text {
display: flex;
flex-direction: column;
}
}

// Style
.callout {
padding: .5em 1em;
border: 1px solid var(--callout-color);
background-color: color-mix(in srgb, var(--callout-color) 10%, transparent);
border-radius: .25em;

i.icon {
color: var(--callout-color);
font-size: 1.5em;
}

&.callout-type-info {
--callout-color: @color-pending;
}

&.callout-type-success {
--callout-color: @color-ok;
}

&.callout-type-warning {
--callout-color: @color-warning;
}

&.callout-type-error {
--callout-color: @color-critical;
}
}
31 changes: 31 additions & 0 deletions src/Common/CalloutType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace ipl\Web\Common;

use ipl\Web\Widget\Icon;

/**
* An enum containing all possible callout types for the {@see Callout} widget.
*/
enum CalloutType: string
{
case Info = 'callout-type-info';
case Success = 'callout-type-success';
case Warning = 'callout-type-warning';
case Error = 'callout-type-error';

/**
* Get the icon element for use in the callout
*
* @return Icon
*/
public function getIcon(): Icon
{
return new Icon(match ($this) {
self::Info => 'circle-info',
self::Success => 'circle-check',
self::Warning => 'warning',
self::Error => 'circle-xmark',
});
}
}
95 changes: 95 additions & 0 deletions src/Widget/Callout.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace ipl\Web\Widget;

use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Html\ValidHtml;
use ipl\I18n\Translation;
use ipl\Web\Common\CalloutType;

/**
* An information box that can be used to display information to the user.
* It consists of a set of standardized colors and icons that can be used to visually distinguish the type of
* information.
* A content string and an optional title can be passed to the constructor.
*/
class Callout extends BaseHtmlElement
{
use Translation;

protected $tag = 'div';

protected $defaultAttributes = ['class' => 'callout'];

/**
* Create a new callout
*
* @param CalloutType $type the type of the callout. The type determines the color and icon that is used.
* @param ValidHtml|string $content the content of the callout
* @param string|null $title an optional title, displayed above the content
*/
public function __construct(
protected CalloutType $type,
protected ValidHtml|string $content,
protected ?string $title = null
) {
$this->addAttributes(Attributes::create(['class' => $type->value]));
}

public function assemble(): void
{
$this->addHtml($this->type->getIcon());

$this->addHtml(HtmlElement::create(
'div',
['class' => 'callout-text'],
[
$this->title
? HtmlElement::create('strong', ['class' => 'callout-title'], new Text($this->title))
: null,
is_string($this->content) ? new Text($this->content) : $this->content,
],
));
}

/**
* Callouts are only as wide as their content.
* Setting it to fullwidth will force the callout to be as wide as its container.
*
* @param bool $fullwidth should the callout be fullwidth
*
* @return $this
*/
public function setFullwidth(bool $fullwidth = true): static
{
if ($fullwidth) {
$this->addAttributes(Attributes::create(['class' => 'callout-fullwidth']));
} else {
$this->removeAttribute('class', 'callout-fullwidth');
}

return $this;
}

/**
* Setting this to true will allow the callout to be used for a single form element.
* This is used to visually align the callout to the content of the form element.
*
* @param bool $isFormElement should the callout be used for a form element
*
* @return $this
*/
public function setFormElement(bool $isFormElement = true): static
{
if ($isFormElement) {
$this->addAttributes(Attributes::create(['class' => 'form-callout']));
} else {
$this->removeAttribute('class', 'from-callout');
}

return $this;
}
}
Loading