lthn.io/app/Core/Front/Components/Component.php
Claude 41a90cbff8
feat: lthn.io API serving live chain data
Fixed: basePath self→static binding, namespace detection, event wiring,
SQLite cache, file cache driver. All Mod Boot classes converted to
$listens pattern for lifecycle event discovery.

Working endpoints:
- /v1/explorer/info — live chain height, difficulty, aliases
- /v1/explorer/stats — formatted chain statistics
- /v1/names/directory — alias directory grouped by type
- /v1/names/available/{name} — name availability check
- /v1/names/lookup/{name} — name details

Co-Authored-By: Charon <charon@lethean.io>
2026-04-03 17:17:42 +01:00

168 lines
3.7 KiB
PHP

<?php
/*
* Core PHP Framework
*
* Licensed under the European Union Public Licence (EUPL) v1.2.
* See LICENSE file for details.
*/
declare(strict_types=1);
namespace Core\Front\Components;
use Closure;
use Illuminate\Contracts\Support\Htmlable;
/**
* Base component class for data-driven UI composition.
*
* Provides fluent interface for building HTML components programmatically.
* Used by MCP tools and agents to compose UIs without Blade templates.
*/
abstract class Component implements Htmlable
{
protected array $attributes = [];
protected array $classes = [];
/**
* Create a new component instance.
*/
public static function make(): static
{
return new static;
}
/**
* Set an HTML attribute.
*/
public function attr(string $key, mixed $value = true): static
{
$this->attributes[$key] = $value;
return $this;
}
/**
* Set multiple attributes.
*/
public function attributes(array $attributes): static
{
$this->attributes = array_merge($this->attributes, $attributes);
return $this;
}
/**
* Add CSS classes.
*/
public function class(string ...$classes): static
{
$this->classes = array_merge($this->classes, $classes);
return $this;
}
/**
* Set the ID attribute.
*/
public function id(string $id): static
{
return $this->attr('id', $id);
}
/**
* Build the attributes string for HTML output.
*/
protected function buildAttributes(array $extraClasses = []): string
{
$attrs = $this->attributes;
$allClasses = array_merge($this->classes, $extraClasses);
if (! empty($allClasses)) {
$existing = $attrs['class'] ?? '';
$attrs['class'] = trim($existing.' '.implode(' ', array_unique($allClasses)));
}
$parts = [];
foreach ($attrs as $key => $value) {
if ($value === true) {
$parts[] = e($key);
} elseif ($value !== false && $value !== null && $value !== '') {
$parts[] = e($key).'="'.e($value).'"';
}
}
return $parts ? ' '.implode(' ', $parts) : '';
}
/**
* Resolve content to string.
*/
protected function resolve(mixed $content): string
{
if ($content === null) {
return '';
}
if ($content instanceof Htmlable) {
return $content->toHtml();
}
if ($content instanceof Closure) {
return $this->resolve($content());
}
if (is_array($content)) {
return implode('', array_map(fn ($item) => $this->resolve($item), $content));
}
return e((string) $content);
}
/**
* Resolve content without escaping (for raw HTML).
*/
protected function raw(mixed $content): string
{
if ($content === null) {
return '';
}
if ($content instanceof Htmlable) {
return $content->toHtml();
}
if ($content instanceof Closure) {
return $this->raw($content());
}
if (is_array($content)) {
return implode('', array_map(fn ($item) => $this->raw($item), $content));
}
return (string) $content;
}
/**
* Render the component to HTML.
*/
abstract public function render(): string;
/**
* Get the HTML string (Htmlable interface).
*/
public function toHtml(): string
{
return $this->render();
}
/**
* Convert to string.
*/
public function __toString(): string
{
return $this->render();
}
}