Files
roi-theme/Public/CtaPost/Infrastructure/Ui/CtaPostRenderer.php
FrankZamora 0846a3bf03 Migración completa a Clean Architecture con componentes funcionales
- Reorganización de estructura: Admin/, Public/, Shared/, Schemas/
- 12 componentes migrados: TopNotificationBar, Navbar, CtaLetsTalk, Hero,
  FeaturedImage, TableOfContents, CtaBoxSidebar, SocialShare, CtaPost,
  RelatedPost, ContactForm, Footer
- Panel de administración con tabs Bootstrap 5 funcionales
- Schemas JSON para configuración de componentes
- Renderers dinámicos con CSSGeneratorService (cero CSS hardcodeado)
- FormBuilders para UI admin con Design System consistente
- Fix: Bootstrap JS cargado en header para tabs funcionales
- Fix: buildTextInput maneja valores mixed (bool/string)
- Eliminación de estructura legacy (src/, admin/, assets/css/componente-*)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 21:20:06 -06:00

188 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
namespace ROITheme\Public\CtaPost\Infrastructure\Ui;
use ROITheme\Shared\Domain\Contracts\RendererInterface;
use ROITheme\Shared\Domain\Contracts\CSSGeneratorInterface;
use ROITheme\Shared\Domain\Entities\Component;
/**
* CtaPostRenderer - Renderiza CTA promocional debajo del contenido
*
* RESPONSABILIDAD: Generar HTML y CSS del componente CTA Post
*
* CARACTERISTICAS:
* - Gradiente configurable
* - Layout responsive (2 columnas en desktop)
* - Boton CTA con icono
* - Estilos 100% desde BD via CSSGenerator
*
* @package ROITheme\Public\CtaPost\Infrastructure\Ui
*/
final class CtaPostRenderer implements RendererInterface
{
public function __construct(
private CSSGeneratorInterface $cssGenerator
) {}
public function render(Component $component): string
{
$data = $component->getData();
if (!$this->isEnabled($data)) {
return '';
}
if (!$this->shouldShowOnCurrentPage($data)) {
return '';
}
$css = $this->generateCSS($data);
$html = $this->buildHTML($data);
return sprintf("<style>%s</style>\n%s", $css, $html);
}
public function supports(string $componentType): bool
{
return $componentType === 'cta-post';
}
private function isEnabled(array $data): bool
{
$value = $data['visibility']['is_enabled'] ?? false;
return $value === true || $value === '1' || $value === 1;
}
private function shouldShowOnCurrentPage(array $data): bool
{
$showOn = $data['visibility']['show_on_pages'] ?? 'posts';
switch ($showOn) {
case 'all':
return true;
case 'posts':
return is_single();
case 'pages':
return is_page();
default:
return true;
}
}
private function generateCSS(array $data): string
{
$colors = $data['colors'] ?? [];
$effects = $data['visual_effects'] ?? [];
$visibility = $data['visibility'] ?? [];
$cssRules = [];
$gradientStart = $colors['gradient_start'] ?? '#FF8600';
$gradientEnd = $colors['gradient_end'] ?? '#FFB800';
$gradientAngle = $effects['gradient_angle'] ?? '135deg';
$buttonBgColor = $colors['button_bg_color'] ?? '#FF8600';
$buttonTextColor = $colors['button_text_color'] ?? '#ffffff';
$buttonHoverBgColor = $colors['button_hover_bg_color'] ?? '#e67a00';
// Container - gradient background
$cssRules[] = $this->cssGenerator->generate('.cta-post-container', [
'background' => "linear-gradient({$gradientAngle}, {$gradientStart} 0%, {$gradientEnd} 100%)",
]);
// Button styles (matching template .cta-button) - Using !important to override Bootstrap btn-light
$cssRules[] = ".cta-post-container .cta-button {
background-color: {$buttonBgColor} !important;
color: {$buttonTextColor} !important;
font-weight: 600;
padding: 0.75rem 2rem;
border: none !important;
border-radius: 8px;
transition: 0.3s;
text-decoration: none;
display: inline-block;
}";
// Button hover state
$cssRules[] = ".cta-post-container .cta-button:hover {
background-color: {$buttonHoverBgColor};
color: {$buttonTextColor};
}";
// Responsive: button full width on mobile
$cssRules[] = "@media (max-width: 768px) {
.cta-post-container .cta-button {
width: 100%;
margin-top: 1rem;
}
}";
// Responsive visibility
$showOnDesktop = $visibility['show_on_desktop'] ?? true;
$showOnDesktop = $showOnDesktop === true || $showOnDesktop === '1' || $showOnDesktop === 1;
$showOnMobile = $visibility['show_on_mobile'] ?? true;
$showOnMobile = $showOnMobile === true || $showOnMobile === '1' || $showOnMobile === 1;
if (!$showOnMobile) {
$cssRules[] = "@media (max-width: 991.98px) {
.cta-post-container { display: none !important; }
}";
}
if (!$showOnDesktop) {
$cssRules[] = "@media (min-width: 992px) {
.cta-post-container { display: none !important; }
}";
}
return implode("\n", $cssRules);
}
private function buildHTML(array $data): string
{
$content = $data['content'] ?? [];
$title = $content['title'] ?? 'Accede a 200,000+ Análisis de Precios Unitarios';
$description = $content['description'] ?? '';
$buttonText = $content['button_text'] ?? 'Ver Catálogo Completo';
$buttonUrl = $content['button_url'] ?? '#';
$buttonIcon = $content['button_icon'] ?? 'bi-arrow-right';
$html = '<div class="my-5 p-4 rounded cta-post-container">';
$html .= ' <div class="row align-items-center">';
// Left column - Content
$html .= ' <div class="col-md-8">';
$html .= sprintf(
' <h3 class="h4 fw-bold text-white mb-2">%s</h3>',
esc_html($title)
);
if (!empty($description)) {
$html .= sprintf(
' <p class="text-white mb-md-0">%s</p>',
esc_html($description)
);
}
$html .= ' </div>';
// Right column - Button
$html .= ' <div class="col-md-4 text-md-end mt-3 mt-md-0">';
$html .= sprintf(
' <a href="%s" class="btn btn-light btn-lg cta-button">%s',
esc_url($buttonUrl),
esc_html($buttonText)
);
if (!empty($buttonIcon)) {
$html .= sprintf(' <i class="bi %s ms-2"></i>', esc_attr($buttonIcon));
}
$html .= '</a>';
$html .= ' </div>';
$html .= ' </div>';
$html .= '</div>';
return $html;
}
}