Files
michaelschiemer/src/Application/Admin/Development/StyleguideController.php
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

302 lines
14 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Application\Admin\Development;
use App\Application\Admin\Service\AdminLayoutProcessor;
use App\Framework\Attributes\Route;
use App\Framework\DateTime\Clock;
use App\Framework\Http\Method;
use App\Framework\Meta\MetaData;
use App\Framework\Router\Result\ViewResult;
use App\Framework\View\Components\Alert;
use App\Framework\View\Components\Badge;
use App\Framework\View\Components\Button;
use App\Framework\View\Components\ButtonGroup;
use App\Framework\View\Components\Card;
use App\Framework\View\Components\Container;
use App\Framework\View\Components\FormCheckbox;
use App\Framework\View\Components\FormInput;
use App\Framework\View\Components\FormRadio;
use App\Framework\View\Components\FormSelect;
use App\Framework\View\Components\FormTextarea;
use App\Framework\Admin\Attributes\AdminPage;
use App\Framework\Admin\Attributes\AdminSection;
use App\Framework\Router\AdminRoutes;
#[AdminSection(name: 'Development', icon: 'code', order: 5, description: 'Development tools and utilities')]
final readonly class StyleguideController
{
public function __construct(
private AdminLayoutProcessor $layoutProcessor,
private Clock $clock,
) {
}
#[AdminPage(title: 'Styleguide', icon: 'tools', section: 'Development', order: 40)]
#[Route(path: '/admin/dev/styleguide', method: Method::GET, name: AdminRoutes::DEV_STYLEGUIDE)]
public function showStyleguide(): ViewResult
{
$metaData = new MetaData(
title: 'Admin Styleguide',
description: 'Design System Components for Admin Interface'
);
$data = [
'title' => 'Component Playground',
'components' => $this->getComponentExamples(),
'phpComponents' => $this->getPhpComponentExamples(),
'colorTokens' => $this->getColorTokens(),
'spacingTokens' => $this->getSpacingTokens(),
'current_year' => $this->clock->now()->format('Y'),
];
$finalData = $this->layoutProcessor->processLayoutFromArray($data);
return new ViewResult(
template: 'styleguide',
metaData: $metaData,
data: $finalData
);
}
/**
* @return array<string, array<string, string>>
*/
private function getComponentExamples(): array
{
return [
'buttons' => [
'primary' => '<button class="admin-button">Primary Button</button>',
'secondary' => '<button class="admin-button admin-button--secondary">Secondary Button</button>',
'success' => '<button class="admin-button admin-button--success">Success Button</button>',
'warning' => '<button class="admin-button admin-button--warning">Warning Button</button>',
'error' => '<button class="admin-button admin-button--error">Error Button</button>',
'small' => '<button class="admin-button admin-button--small">Small Button</button>',
'large' => '<button class="admin-button admin-button--large">Large Button</button>',
],
'cards' => [
'basic' => '
<div class="admin-card">
<div class="admin-card__header">
<h3 class="admin-card__title">Basic Card</h3>
</div>
<div class="admin-card__content">
This is a basic admin card with header and content.
</div>
</div>
',
'status_success' => '
<div class="admin-card status-card status-card--success">
<div class="admin-card__header">
<h3 class="admin-card__title">✅ Success Card</h3>
<span class="admin-table__status admin-table__status--success">
<span class="status-indicator status-indicator--success"></span>
PASS
</span>
</div>
<div class="admin-card__content">
This is a success status card.
</div>
</div>
',
'metric' => '
<div class="admin-card metric-card">
<div class="metric-card__value">1,234</div>
<div class="metric-card__label">Total Users</div>
<div class="metric-card__change metric-card__change--positive">+12% this month</div>
</div>
',
],
'forms' => [
'input' => '<input type="text" class="admin-input" placeholder="Enter text here">',
'select' => '
<select class="admin-input admin-select">
<option>Choose option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
',
'search' => '
<div class="admin-search">
<input type="search" class="admin-input admin-search__input" placeholder="Search...">
</div>
',
],
'tables' => [
'basic' => '
<div class="admin-table-wrapper">
<div class="admin-table-wrapper__header">
<h3 class="admin-table-wrapper__title">Sample Data</h3>
</div>
<table class="admin-table">
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Value</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sample Item 1</td>
<td>
<span class="admin-table__status admin-table__status--success">
<span class="status-indicator status-indicator--success"></span>
ACTIVE
</span>
</td>
<td>$123.45</td>
<td class="admin-table__actions">
<a href="#" class="admin-table__action">Edit</a>
<a href="#" class="admin-table__action admin-table__action--danger">Delete</a>
</td>
</tr>
<tr>
<td>Sample Item 2</td>
<td>
<span class="admin-table__status admin-table__status--warning">
<span class="status-indicator status-indicator--warning"></span>
PENDING
</span>
</td>
<td>$67.89</td>
<td class="admin-table__actions">
<a href="#" class="admin-table__action">Edit</a>
<a href="#" class="admin-table__action admin-table__action--danger">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
',
],
];
}
/**
* @return array<string, array<string, string>>
*/
private function getColorTokens(): array
{
return [
'primary' => [
'accent' => 'var(--accent)',
'bg' => 'var(--bg)',
'bg-alt' => 'var(--bg-alt)',
'text' => 'var(--text)',
'muted' => 'var(--muted)',
'border' => 'var(--border)',
],
'semantic' => [
'success' => 'var(--success)',
'warning' => 'var(--warning)',
'error' => 'var(--error)',
'info' => 'var(--info-base)',
],
];
}
/**
* @return array<string, string>
*/
private function getSpacingTokens(): array
{
return [
'space-sm' => 'var(--space-sm)',
'space-md' => 'var(--space-md)',
'space-lg' => 'var(--space-lg)',
'radius-md' => 'var(--radius-md)',
'radius-lg' => 'var(--radius-lg)',
];
}
/**
* @return array<string, array<string, mixed>>
*/
private function getPhpComponentExamples(): array
{
return [
'buttons' => [
'primary' => Button::primary('Primary Button'),
'secondary' => Button::secondary('Secondary Button'),
'danger' => Button::danger('Delete'),
'success' => Button::success('Save'),
'ghost' => Button::ghost('Cancel'),
'link' => Button::link('View Details', '/admin/details'),
'submit' => Button::primary('Submit Form')->asSubmit(),
'small' => Button::primary('Small')->withSize('sm'),
'large' => Button::primary('Large')->withSize('lg'),
'full_width' => Button::primary('Full Width')->fullWidth(),
],
'button_groups' => [
'horizontal' => ButtonGroup::create(
Button::primary('Left'),
Button::secondary('Center'),
Button::secondary('Right')
),
'vertical' => ButtonGroup::create(
Button::primary('Top'),
Button::secondary('Middle'),
Button::secondary('Bottom')
)->asVertical(),
],
'badges' => [
'default' => Badge::create('Default'),
'primary' => Badge::primary('Primary'),
'success' => Badge::success('Success'),
'warning' => Badge::warning('Warning'),
'danger' => Badge::danger('Danger'),
'info' => Badge::info('Info'),
'pill' => Badge::primary('Pill Badge')->asPill(),
'small' => Badge::success('Small')->withSize('sm'),
'large' => Badge::danger('Large')->withSize('lg'),
],
'alerts' => [
'info' => Alert::info('This is an informational message.'),
'success' => Alert::success('Operation completed successfully!'),
'warning' => Alert::warning('Please review this warning.'),
'danger' => Alert::danger('An error occurred!'),
'with_title' => Alert::success('Operation completed successfully!', 'Success'),
'dismissible' => Alert::info('You can dismiss this alert.')->withDismissible(),
],
'forms' => [
'text_input' => FormInput::text('username', 'Username', ''),
'email_input' => FormInput::email('email', 'Email Address', ''),
'password_input' => FormInput::password('password', 'Password'),
'required_input' => FormInput::text('required_field', 'Required Field')->withRequired(),
'error_input' => FormInput::email('error_email', 'Email')->withError('Invalid email address'),
'textarea' => FormTextarea::create('description', 'Description', ''),
'select' => FormSelect::create(
'status',
['active' => 'Active', 'pending' => 'Pending', 'inactive' => 'Inactive'],
'Status'
),
'checkbox' => FormCheckbox::create('agree', 'I agree to the terms and conditions', '1'),
'radio_group' => FormRadio::create('size', 'small', 'Small')
. FormRadio::create('size', 'medium', 'Medium')->withChecked()
. FormRadio::create('size', 'large', 'Large'),
],
'cards' => [
'basic' => Card::create('This is a basic card with just content.'),
'with_title' => Card::withTitle('Card Title', 'This card has a title and content.'),
'with_subtitle' => Card::withTitle('Card Title', 'Card content here.')
->withSubtitle('This is a subtitle'),
'with_footer' => Card::withTitle('Card with Footer', 'Card content goes here.')
->withFooter('Footer text or actions'),
'full_card' => Card::withTitle('Complete Card', 'This is the main content of the card.')
->withSubtitle('Optional subtitle')
->withFooter(Button::primary('Action')),
],
'containers' => [
'default' => Container::create('<p>Default container with max-width: 1024px</p>'),
'small' => Container::small('<p>Small container with max-width: 640px</p>'),
'large' => Container::large('<p>Large container with max-width: 1280px</p>'),
'fluid' => Container::fluid('<p>Fluid container with no max-width</p>'),
],
];
}
}