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
- 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
302 lines
14 KiB
PHP
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>'),
|
|
],
|
|
];
|
|
}
|
|
}
|