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>
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ROITheme\Admin\FeaturedImage\Infrastructure\Ui;
|
||||
|
||||
use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer;
|
||||
|
||||
final class FeaturedImageFormBuilder
|
||||
{
|
||||
public function __construct(
|
||||
private AdminDashboardRenderer $renderer
|
||||
) {}
|
||||
|
||||
public function buildForm(string $componentId): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
$html .= $this->buildHeader($componentId);
|
||||
|
||||
$html .= '<div class="row g-3">';
|
||||
$html .= ' <div class="col-lg-6">';
|
||||
$html .= $this->buildVisibilityGroup($componentId);
|
||||
$html .= $this->buildContentGroup($componentId);
|
||||
$html .= ' </div>';
|
||||
$html .= ' <div class="col-lg-6">';
|
||||
$html .= $this->buildSpacingGroup($componentId);
|
||||
$html .= $this->buildEffectsGroup($componentId);
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function buildHeader(string $componentId): string
|
||||
{
|
||||
$html = '<div class="rounded p-4 mb-4 shadow text-white" ';
|
||||
$html .= 'style="background: linear-gradient(135deg, #0E2337 0%, #1e3a5f 100%); border-left: 4px solid #FF8600;">';
|
||||
$html .= ' <div class="d-flex align-items-center justify-content-between flex-wrap gap-3">';
|
||||
$html .= ' <div>';
|
||||
$html .= ' <h3 class="h4 mb-1 fw-bold">';
|
||||
$html .= ' <i class="bi bi-image me-2" style="color: #FF8600;"></i>';
|
||||
$html .= ' Configuracion de Imagen Destacada';
|
||||
$html .= ' </h3>';
|
||||
$html .= ' <p class="mb-0 small" style="opacity: 0.85;">';
|
||||
$html .= ' Personaliza la imagen destacada de los posts';
|
||||
$html .= ' </p>';
|
||||
$html .= ' </div>';
|
||||
$html .= ' <button type="button" class="btn btn-sm btn-outline-light btn-reset-defaults" data-component="featured_image">';
|
||||
$html .= ' <i class="bi bi-arrow-counterclockwise me-1"></i>';
|
||||
$html .= ' Restaurar valores por defecto';
|
||||
$html .= ' </button>';
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function buildVisibilityGroup(string $componentId): string
|
||||
{
|
||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
||||
$html .= ' <div class="card-body">';
|
||||
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
||||
$html .= ' <i class="bi bi-toggle-on me-2" style="color: #FF8600;"></i>';
|
||||
$html .= ' Visibilidad';
|
||||
$html .= ' </h5>';
|
||||
|
||||
$enabled = $this->renderer->getFieldValue($componentId, 'visibility', 'is_enabled', true);
|
||||
$html .= ' <div class="mb-2">';
|
||||
$html .= ' <div class="form-check form-switch">';
|
||||
$html .= ' <input class="form-check-input" type="checkbox" id="featuredImageEnabled" ';
|
||||
$html .= checked($enabled, true, false) . '>';
|
||||
$html .= ' <label class="form-check-label small" for="featuredImageEnabled">';
|
||||
$html .= ' <i class="bi bi-power me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' <strong>Mostrar imagen destacada</strong>';
|
||||
$html .= ' </label>';
|
||||
$html .= ' </div>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$showOnDesktop = $this->renderer->getFieldValue($componentId, 'visibility', 'show_on_desktop', true);
|
||||
$html .= ' <div class="mb-2">';
|
||||
$html .= ' <div class="form-check form-switch">';
|
||||
$html .= ' <input class="form-check-input" type="checkbox" id="featuredImageShowOnDesktop" ';
|
||||
$html .= checked($showOnDesktop, true, false) . '>';
|
||||
$html .= ' <label class="form-check-label small" for="featuredImageShowOnDesktop">';
|
||||
$html .= ' <i class="bi bi-display me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' <strong>Mostrar en Desktop</strong>';
|
||||
$html .= ' </label>';
|
||||
$html .= ' </div>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$showOnMobile = $this->renderer->getFieldValue($componentId, 'visibility', 'show_on_mobile', true);
|
||||
$html .= ' <div class="mb-2">';
|
||||
$html .= ' <div class="form-check form-switch">';
|
||||
$html .= ' <input class="form-check-input" type="checkbox" id="featuredImageShowOnMobile" ';
|
||||
$html .= checked($showOnMobile, true, false) . '>';
|
||||
$html .= ' <label class="form-check-label small" for="featuredImageShowOnMobile">';
|
||||
$html .= ' <i class="bi bi-phone me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' <strong>Mostrar en Mobile</strong>';
|
||||
$html .= ' </label>';
|
||||
$html .= ' </div>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$showOnPages = $this->renderer->getFieldValue($componentId, 'visibility', 'show_on_pages', 'posts');
|
||||
$html .= ' <div class="mb-0 mt-3">';
|
||||
$html .= ' <label for="featuredImageShowOnPages" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' <i class="bi bi-file-earmark-text me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' Mostrar en';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <select id="featuredImageShowOnPages" class="form-select form-select-sm">';
|
||||
$html .= ' <option value="all" ' . selected($showOnPages, 'all', false) . '>Todas las paginas</option>';
|
||||
$html .= ' <option value="posts" ' . selected($showOnPages, 'posts', false) . '>Solo posts individuales</option>';
|
||||
$html .= ' <option value="pages" ' . selected($showOnPages, 'pages', false) . '>Solo paginas</option>';
|
||||
$html .= ' </select>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function buildContentGroup(string $componentId): string
|
||||
{
|
||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
||||
$html .= ' <div class="card-body">';
|
||||
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
||||
$html .= ' <i class="bi bi-card-image me-2" style="color: #FF8600;"></i>';
|
||||
$html .= ' Contenido';
|
||||
$html .= ' </h5>';
|
||||
|
||||
$imageSize = $this->renderer->getFieldValue($componentId, 'content', 'image_size', 'roi-featured-large');
|
||||
$html .= ' <div class="mb-3">';
|
||||
$html .= ' <label for="featuredImageSize" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' <i class="bi bi-aspect-ratio me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' Tamano de imagen';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <select id="featuredImageSize" class="form-select form-select-sm">';
|
||||
$html .= ' <option value="roi-featured-large" ' . selected($imageSize, 'roi-featured-large', false) . '>Grande (1200x600)</option>';
|
||||
$html .= ' <option value="roi-featured-medium" ' . selected($imageSize, 'roi-featured-medium', false) . '>Mediano (800x400)</option>';
|
||||
$html .= ' <option value="full" ' . selected($imageSize, 'full', false) . '>Original (tamano completo)</option>';
|
||||
$html .= ' </select>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$lazyLoading = $this->renderer->getFieldValue($componentId, 'content', 'lazy_loading', true);
|
||||
$html .= ' <div class="mb-2">';
|
||||
$html .= ' <div class="form-check form-switch">';
|
||||
$html .= ' <input class="form-check-input" type="checkbox" id="featuredImageLazyLoading" ';
|
||||
$html .= checked($lazyLoading, true, false) . '>';
|
||||
$html .= ' <label class="form-check-label small" for="featuredImageLazyLoading">';
|
||||
$html .= ' <i class="bi bi-lightning me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' <strong>Carga diferida (lazy loading)</strong>';
|
||||
$html .= ' </label>';
|
||||
$html .= ' </div>';
|
||||
$html .= ' <small class="text-muted">Mejora rendimiento cargando imagen cuando es visible</small>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$linkToMedia = $this->renderer->getFieldValue($componentId, 'content', 'link_to_media', false);
|
||||
$html .= ' <div class="mb-0">';
|
||||
$html .= ' <div class="form-check form-switch">';
|
||||
$html .= ' <input class="form-check-input" type="checkbox" id="featuredImageLinkToMedia" ';
|
||||
$html .= checked($linkToMedia, true, false) . '>';
|
||||
$html .= ' <label class="form-check-label small" for="featuredImageLinkToMedia">';
|
||||
$html .= ' <i class="bi bi-link-45deg me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' <strong>Enlazar a imagen completa</strong>';
|
||||
$html .= ' </label>';
|
||||
$html .= ' </div>';
|
||||
$html .= ' <small class="text-muted">Abre la imagen en tamano completo al hacer clic</small>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function buildSpacingGroup(string $componentId): string
|
||||
{
|
||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
||||
$html .= ' <div class="card-body">';
|
||||
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
||||
$html .= ' <i class="bi bi-arrows-move me-2" style="color: #FF8600;"></i>';
|
||||
$html .= ' Espaciado';
|
||||
$html .= ' </h5>';
|
||||
|
||||
$html .= ' <div class="row g-2 mb-0">';
|
||||
|
||||
$marginTop = $this->renderer->getFieldValue($componentId, 'spacing', 'margin_top', '1rem');
|
||||
$html .= ' <div class="col-6">';
|
||||
$html .= ' <label for="featuredImageMarginTop" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' Margen superior';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <input type="text" id="featuredImageMarginTop" class="form-control form-control-sm" ';
|
||||
$html .= ' value="' . esc_attr($marginTop) . '" placeholder="1rem">';
|
||||
$html .= ' </div>';
|
||||
|
||||
$marginBottom = $this->renderer->getFieldValue($componentId, 'spacing', 'margin_bottom', '2rem');
|
||||
$html .= ' <div class="col-6">';
|
||||
$html .= ' <label for="featuredImageMarginBottom" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' Margen inferior';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <input type="text" id="featuredImageMarginBottom" class="form-control form-control-sm" ';
|
||||
$html .= ' value="' . esc_attr($marginBottom) . '" placeholder="2rem">';
|
||||
$html .= ' </div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function buildEffectsGroup(string $componentId): string
|
||||
{
|
||||
$html = '<div class="card shadow-sm mb-3" style="border-left: 4px solid #1e3a5f;">';
|
||||
$html .= ' <div class="card-body">';
|
||||
$html .= ' <h5 class="fw-bold mb-3" style="color: #1e3a5f;">';
|
||||
$html .= ' <i class="bi bi-magic me-2" style="color: #FF8600;"></i>';
|
||||
$html .= ' Efectos Visuales';
|
||||
$html .= ' </h5>';
|
||||
|
||||
$borderRadius = $this->renderer->getFieldValue($componentId, 'visual_effects', 'border_radius', '12px');
|
||||
$html .= ' <div class="mb-2">';
|
||||
$html .= ' <label for="featuredImageBorderRadius" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' Radio de bordes';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <input type="text" id="featuredImageBorderRadius" class="form-control form-control-sm" ';
|
||||
$html .= ' value="' . esc_attr($borderRadius) . '" placeholder="12px">';
|
||||
$html .= ' </div>';
|
||||
|
||||
$boxShadow = $this->renderer->getFieldValue($componentId, 'visual_effects', 'box_shadow', '0 8px 24px rgba(0, 0, 0, 0.1)');
|
||||
$html .= ' <div class="mb-3">';
|
||||
$html .= ' <label for="featuredImageBoxShadow" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' Sombra';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <input type="text" id="featuredImageBoxShadow" class="form-control form-control-sm" ';
|
||||
$html .= ' value="' . esc_attr($boxShadow) . '">';
|
||||
$html .= ' </div>';
|
||||
|
||||
$hoverEffect = $this->renderer->getFieldValue($componentId, 'visual_effects', 'hover_effect', true);
|
||||
$html .= ' <div class="mb-2">';
|
||||
$html .= ' <div class="form-check form-switch">';
|
||||
$html .= ' <input class="form-check-input" type="checkbox" id="featuredImageHoverEffect" ';
|
||||
$html .= checked($hoverEffect, true, false) . '>';
|
||||
$html .= ' <label class="form-check-label small" for="featuredImageHoverEffect">';
|
||||
$html .= ' <i class="bi bi-hand-index me-1" style="color: #FF8600;"></i>';
|
||||
$html .= ' <strong>Efecto hover</strong>';
|
||||
$html .= ' </label>';
|
||||
$html .= ' </div>';
|
||||
$html .= ' <small class="text-muted">Aplica efecto de escala sutil al pasar el mouse</small>';
|
||||
$html .= ' </div>';
|
||||
|
||||
$html .= ' <div class="row g-2 mb-0">';
|
||||
|
||||
$hoverScale = $this->renderer->getFieldValue($componentId, 'visual_effects', 'hover_scale', '1.02');
|
||||
$html .= ' <div class="col-6">';
|
||||
$html .= ' <label for="featuredImageHoverScale" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' Escala en hover';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <input type="text" id="featuredImageHoverScale" class="form-control form-control-sm" ';
|
||||
$html .= ' value="' . esc_attr($hoverScale) . '" placeholder="1.02">';
|
||||
$html .= ' </div>';
|
||||
|
||||
$transitionDuration = $this->renderer->getFieldValue($componentId, 'visual_effects', 'transition_duration', '0.3s');
|
||||
$html .= ' <div class="col-6">';
|
||||
$html .= ' <label for="featuredImageTransitionDuration" class="form-label small mb-1 fw-semibold">';
|
||||
$html .= ' Duracion transicion';
|
||||
$html .= ' </label>';
|
||||
$html .= ' <input type="text" id="featuredImageTransitionDuration" class="form-control form-control-sm" ';
|
||||
$html .= ' value="' . esc_attr($transitionDuration) . '" placeholder="0.3s">';
|
||||
$html .= ' </div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
|
||||
$html .= ' </div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user