Files
michaelschiemer/src/Framework/View/Components/Card.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

174 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\View\Components;
use App\Framework\View\Attributes\ComponentName;
use App\Framework\View\ValueObjects\HtmlAttributes;
use App\Framework\View\ValueObjects\HtmlElement;
use App\Framework\View\ValueObjects\HtmlTag;
use App\Framework\View\ValueObjects\StandardHtmlElement;
use App\Framework\View\ValueObjects\TagName;
#[ComponentName('card')]
final readonly class Card implements HtmlElement
{
public HtmlTag $tag;
public HtmlAttributes $attributes;
public string $content;
public function __construct(
string $bodyContent,
public ?string $title = null,
public ?string $subtitle = null,
public ?string $footer = null,
public ?string $imageSrc = null,
public ?string $imageAlt = null,
public string $variant = 'default',
public HtmlAttributes $additionalAttributes = new HtmlAttributes()
) {
$this->tag = new HtmlTag(TagName::DIV);
$classes = ['card', "card--{$this->variant}"];
$this->attributes = HtmlAttributes::empty()
->withClass(implode(' ', $classes));
foreach ($this->additionalAttributes->attributes as $name => $value) {
$this->attributes = $this->attributes->with($name, $value);
}
$this->content = $this->buildContent($bodyContent);
}
public static function create(string $bodyContent): self
{
return new self(bodyContent: $bodyContent);
}
public static function withTitle(string $title, string $bodyContent): self
{
return new self(bodyContent: $bodyContent, title: $title);
}
public static function withImage(string $imageSrc, string $bodyContent, ?string $imageAlt = null): self
{
return new self(bodyContent: $bodyContent, imageSrc: $imageSrc, imageAlt: $imageAlt);
}
public function withSubtitle(string $subtitle): self
{
// Note: Can't access bodyContent from constructor, need to rebuild from content
return new self(
bodyContent: '', // Will be rebuilt in buildContent
title: $this->title,
subtitle: $subtitle,
footer: $this->footer,
imageSrc: $this->imageSrc,
imageAlt: $this->imageAlt,
variant: $this->variant,
additionalAttributes: $this->additionalAttributes
);
}
public function withFooter(string|HtmlElement $footer): self
{
return new self(
bodyContent: '', // Will be rebuilt in buildContent
title: $this->title,
subtitle: $this->subtitle,
footer: (string) $footer,
imageSrc: $this->imageSrc,
imageAlt: $this->imageAlt,
variant: $this->variant,
additionalAttributes: $this->additionalAttributes
);
}
public function withVariant(string $variant): self
{
return new self(
bodyContent: '', // Will be rebuilt in buildContent
title: $this->title,
subtitle: $this->subtitle,
footer: $this->footer,
imageSrc: $this->imageSrc,
imageAlt: $this->imageAlt,
variant: $variant,
additionalAttributes: $this->additionalAttributes
);
}
private function buildContent(string $bodyContent): string
{
$elements = [];
// Image
if ($this->imageSrc !== null) {
$imgAttrs = HtmlAttributes::empty()
->with('src', $this->imageSrc)
->withClass('card__image');
if ($this->imageAlt !== null) {
$imgAttrs = $imgAttrs->with('alt', $this->imageAlt);
}
$elements[] = StandardHtmlElement::create(TagName::IMG, $imgAttrs);
}
// Header (title + subtitle)
if ($this->title !== null || $this->subtitle !== null) {
$headerElements = [];
if ($this->title !== null) {
$headerElements[] = StandardHtmlElement::create(
TagName::H3,
HtmlAttributes::empty()->withClass('card__title'),
$this->title
);
}
if ($this->subtitle !== null) {
$headerElements[] = StandardHtmlElement::create(
TagName::P,
HtmlAttributes::empty()->withClass('card__subtitle'),
$this->subtitle
);
}
$elements[] = StandardHtmlElement::create(
TagName::DIV,
HtmlAttributes::empty()->withClass('card__header'),
implode('', array_map('strval', $headerElements))
);
}
// Body
$elements[] = StandardHtmlElement::create(
TagName::DIV,
HtmlAttributes::empty()->withClass('card__body'),
$bodyContent
);
// Footer
if ($this->footer !== null) {
$elements[] = StandardHtmlElement::create(
TagName::DIV,
HtmlAttributes::empty()->withClass('card__footer'),
$this->footer
);
}
return implode('', array_map('strval', $elements));
}
public function __toString(): string
{
return (string) StandardHtmlElement::create(
$this->tag->name,
$this->attributes,
$this->content
);
}
}