Skip to content

Commit

Permalink
[FEATURE] Introduce directives for bootstrap cards
Browse files Browse the repository at this point in the history
  • Loading branch information
linawolf committed Apr 20, 2024
1 parent 61a414c commit 3bfed7b
Show file tree
Hide file tree
Showing 9 changed files with 420 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

use phpDocumentor\Guides\Bootstrap\Directives\AccordionDirective;
use phpDocumentor\Guides\Bootstrap\Directives\AccordionItemDirective;
use phpDocumentor\Guides\Bootstrap\Directives\CardDirective;
use phpDocumentor\Guides\Bootstrap\Directives\CardFooterDirective;
use phpDocumentor\Guides\Bootstrap\Directives\CardGridDirective;
Expand All @@ -26,6 +28,9 @@
->bind('$startingRule', service(DirectiveContentRule::class))
->instanceof(BaseDirective::class)
->tag('phpdoc.guides.directive')
->set(AccordionDirective::class)
->set(AccordionItemDirective::class)
->set(CardDirective::class)
->set(CardDirective::class)
->set(CardFooterDirective::class)
->set(CardHeaderDirective::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="accordion {%- if node.classes %} {{ node.classesString }}{% endif -%}" id="{{ node.anchor }}">
{% for item in node.value %}
<div class="accordion-item {%- if item.classes %} {{ item.classesString }}{% endif -%}">
<h{{ item.title.level }} class="accordion-header" id="{{ item.anchor }}-heading">
<button class="accordion-button {%- if not item.show %} collapsed{% endif -%}" type="button" data-bs-toggle="collapse" data-bs-target="#{{ item.anchor }}"
aria-expanded="{%- if item.show %}true{% else %}false{% endif -%}" aria-controls="{{ item.anchor }}">
{{ renderNode(item.title.value) }}
</button>
</h{{ item.title.level }}>
<div id="{{ item.anchor }}" class="accordion-collapse collapse {%- if item.show %} show{% endif -%}" aria-labelledby="{{ item.anchor }}-heading"
data-bs-parent="#{{ node.anchor }}">
<div class="accordion-body">
{{ renderNode(item.value) }}
</div>
</div>
</div>
{%- endfor %}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Bootstrap\Directives;

use phpDocumentor\Guides\Bootstrap\Nodes\AccordionItemNode;
use phpDocumentor\Guides\Bootstrap\Nodes\AccordionNode;
use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RestructuredText\Directives\SubDirective;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;
use phpDocumentor\Guides\RestructuredText\Parser\Productions\Rule;
use Psr\Log\LoggerInterface;

class AccordionDirective extends SubDirective
{
public const NAME = 'accordion';

public function __construct(
protected Rule $startingRule,
private readonly LoggerInterface $logger,
) {
parent::__construct($startingRule);
}

public function getName(): string
{
return self::NAME;
}

protected function processSub(
BlockContext $blockContext,
CollectionNode $collectionNode,
Directive $directive,
): Node|null {
$originalChildren = $collectionNode->getChildren();
$children = [];
foreach ($originalChildren as $child) {
if ($child instanceof AccordionItemNode) {
$children[] = $child;
} else {
$this->logger->warning('An accordion may only accordion-items. ', $blockContext->getLoggerInformation());
}
}

$id = $directive->getOption('name')->toString();
if ($id === '') {
$id = 'accordion';
$this->logger->warning('An accordion must have a unique name as parameter. ', $blockContext->getLoggerInformation());
}

return new AccordionNode(
$this->getName(),
$directive->getData(),
$directive->getDataNode() ?? new InlineCompoundNode(),
$children,
$id,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Bootstrap\Directives;

use phpDocumentor\Guides\Bootstrap\Nodes\AccordionItemNode;
use phpDocumentor\Guides\Bootstrap\Nodes\CardNode;
use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Nodes\TitleNode;
use phpDocumentor\Guides\ReferenceResolvers\AnchorNormalizer;
use phpDocumentor\Guides\RestructuredText\Directives\SubDirective;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;
use phpDocumentor\Guides\RestructuredText\Parser\Productions\Rule;
use phpDocumentor\Guides\RestructuredText\TextRoles\GenericLinkProvider;
use Psr\Log\LoggerInterface;

use function intval;

class AccordionItemDirective extends SubDirective
{
public const NAME = 'accordion-item';

public function __construct(
protected Rule $startingRule,
GenericLinkProvider $genericLinkProvider,
private readonly AnchorNormalizer $anchorReducer,
private readonly LoggerInterface $logger,
) {
parent::__construct($startingRule);

$genericLinkProvider->addGenericLink(self::NAME, CardNode::LINK_TYPE, CardNode::LINK_PREFIX);
}

public function getName(): string
{
return self::NAME;
}

protected function processSub(
BlockContext $blockContext,
CollectionNode $collectionNode,
Directive $directive,
): Node|null {
$headerLevel = intval($directive->getOption('header-level')->getValue());
if ($headerLevel <= 0) {
$headerLevel = 3;
}

if ($directive->getDataNode() !== null) {
$title = new TitleNode($directive->getDataNode(), $headerLevel, $this->getName());
} else {
$title = TitleNode::fromString('Accordion Item')->setLevel($headerLevel);
$this->logger->warning('An accordion item must have a title. Usage: .. accordion-item:: [title] ', $blockContext->getLoggerInformation());
}

$children = $collectionNode->getChildren();

$id = $directive->getOption('name')->toString();
$show = $directive->hasOption('show');
if ($id === '') {
$id = 'accordion';
$this->logger->warning('An accordion item must have a unique name as parameter. ', $blockContext->getLoggerInformation());
}

$id = $this->anchorReducer->reduceAnchor($id);

return new AccordionItemNode(
$this->getName(),
$directive->getData(),
$directive->getDataNode() ?? new InlineCompoundNode(),
$title,
$children,
$id,
$show,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Bootstrap\Nodes;

use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\LinkTargetNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Nodes\OptionalLinkTargetsNode;
use phpDocumentor\Guides\Nodes\PrefixedLinkTargetNode;
use phpDocumentor\Guides\Nodes\TitleNode;
use phpDocumentor\Guides\RestructuredText\Nodes\GeneralDirectiveNode;

final class AccordionItemNode extends GeneralDirectiveNode implements LinkTargetNode, OptionalLinkTargetsNode, PrefixedLinkTargetNode
{
public const LINK_TYPE = 'std:accordion';
public const LINK_PREFIX = 'accordion-';

/** @param list<Node> $value */
public function __construct(
protected readonly string $name,
protected readonly string $plainContent,
protected readonly InlineCompoundNode $content,
protected readonly TitleNode $title,
array $value = [],
private readonly string $id = '',
private readonly bool $show = false,
) {
parent::__construct($name, $plainContent, $content, $value);
}

public function getTitle(): TitleNode
{
return $this->title;
}

public function getName(): string
{
return $this->name;
}

public function getPlainContent(): string
{
return $this->plainContent;
}

public function getContent(): InlineCompoundNode
{
return $this->content;
}

public function getLinkType(): string
{
return self::LINK_TYPE;
}

public function getId(): string
{
return $this->id;
}

public function getAnchor(): string
{
return self::LINK_PREFIX . $this->id;
}

public function getLinkText(): string
{
return $this->getTitle()->toString();
}

public function isNoindex(): bool
{
return $this->id === '';
}

public function getPrefix(): string
{
return self::LINK_PREFIX;
}

public function isShow(): bool
{
return $this->show;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Bootstrap\Nodes;

use phpDocumentor\Guides\Nodes\InlineCompoundNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\RestructuredText\Nodes\GeneralDirectiveNode;

final class AccordionNode extends GeneralDirectiveNode
{
/** @param list<Node> $value */
public function __construct(
protected readonly string $name,
protected readonly string $plainContent,
protected readonly InlineCompoundNode $content,
array $value = [],
protected readonly string $id = 'accordion',
) {
parent::__construct($name, $plainContent, $content, $value);
}

public function getId(): string
{
return $this->id;
}

public function getAnchor(): string
{
return 'accordion-parent-' . $this->id;
}
}
7 changes: 7 additions & 0 deletions packages/guides/src/Nodes/TitleNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ public function getLevel(): int
return $this->level;
}

public function setLevel(int $level): TitleNode
{
$this->level = $level;

return $this;
}

public function setTarget(string $target): void
{
$this->target = $target;
Expand Down
Loading

0 comments on commit 3bfed7b

Please sign in to comment.