1. Go to this page and download the library: Download c975l/ui-bundle library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
use c975L\UiBundle\Contract\HasBlocksInterface;
use c975L\UiBundle\Entity\Block;
use c975L\UiBundle\Entity\Trait\HasBlocksTrait;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
class Page implements HasBlocksInterface
{
use HasBlocksTrait;
#[ORM\ManyToMany(targetEntity: Block::class, cascade: ['persist', 'remove'])]
#[ORM\JoinTable(name: 'site_page_block')]
#[ORM\OrderBy(['position' => 'ASC'])]
private Collection $blocks;
public function __construct()
{
$this->blocks = new ArrayCollection();
}
}
use c975L\UiBundle\Form\BlockType;
class PageCrudController extends AbstractCrudController
{
public function configureFields(string $pageName): iterable
{
return [
// ...
CollectionField::new('blocks')
->setLabel(t('label.blocks', [], 'ui'))
->setEntryType(BlockType::class)
->allowAdd()
->allowDelete()
->setFormTypeOption('by_reference', false)
->hideOnIndex(),
];
}
}
use c975L\UiBundle\Form\Block\HasAnchorFieldTrait;
use c975L\UiBundle\Service\BlockAnchorSlugger;
class MySectionType extends AbstractType
{
use HasAnchorFieldTrait;
public function __construct(private readonly BlockAnchorSlugger $anchorSlugger)
{
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$this->addAnchorField($builder, $this->anchorSlugger); // 2nd arg: title field name, defaults to "title"
// ...your own fields...
}
}
use c975L\UiBundle\Form\Block\HasBackgroundFieldTrait;
class MySectionType extends AbstractType
{
use HasBackgroundFieldTrait;
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$this->addBackgroundField($builder);
// ...your own fields...
}
}
use c975L\UiBundle\Contract\PlaceholderMediaProviderInterface;
class ShowcasePlaceholderMediaProvider implements PlaceholderMediaProviderInterface
{
public function getPlaceholderMedia(): array
{
return [
'images' => ['medias/showcase/photo-1.webp', 'medias/showcase/photo-2.webp'],
'video' => 'medias/showcase/clip.mp4',
'video_embed' => 'medias/showcase/clip-embed.html',
'audio' => 'medias/showcase/loop.mp3',
'document' => 'medias/showcase/brochure.pdf',
];
}
}
use c975L\UiBundle\Contract\BlockFixtureProviderInterface;
class BookingBlockFixtureProvider implements BlockFixtureProviderInterface
{
public function getFixtures(): array
{
return [
'booking' => [
'' => ['title' => 'Réserver une table'],
],
];
}
}
use c975L\UiBundle\Contract\GalleryShowcaseProviderInterface;
use Twig\Environment;
class BookingGalleryShowcaseProvider implements GalleryShowcaseProviderInterface
{
public function __construct(private Environment $twig) {}
public function getShowcases(): array
{
return [
'Booking widget' => [
'description' => 'Available layouts for the standalone booking widget.',
// "kind" ties this to "booking"'s own category and suppresses its own regular preview
// card (which would otherwise show up empty right next to this one) - use null if there's
// no real block kind at all (e.g. share_buttons()). "category" overrides the category
// directly instead (no suppression) - for a kind-less showcase that still belongs next
// to a related one, e.g. reusing a sibling kind's own category key.
'kind' => 'booking',
'variants' => [
'Compact' => $this->twig->render('@App/booking/widget.html.twig', ['layout' => 'compact']),
'Full' => $this->twig->render('@App/booking/widget.html.twig', ['layout' => 'full']),
],
],
];
}
}
use c975L\UiBundle\Form\CaptchaType;
$builder->add('captcha', CaptchaType::class, [
// Reported to Google alongside the token, so the admin console can break scores down per form
'action_name' => 'contact',
]);
use c975L\UiBundle\Contract\MediaUsageProviderInterface;
use c975L\UiBundle\Entity\Media;
class MyMediaUsageProvider implements MediaUsageProviderInterface
{
public function getUsages(array $medias): array
{
// [mediaId => [['label' => string, 'url' => ?string], ...], ...]
return [...];
}
}
use c975L\UiBundle\Contract\BundleStylesheetProviderInterface;
class StylesheetProvider implements BundleStylesheetProviderInterface
{
public function getStylesheets(): array
{
return [
'bundles/mybundle/css/styles.min.css', // local public asset
'assets/styles/themes/mybundle.css', // the app's own sheet, served by AssetMapper
'https://cdn.example.com/lib/styles.min.css', // CDN URL, passed through as-is
];
}
}
namespace App\Service;
use c975L\UiBundle\Contract\BundleStylesheetProviderInterface;
class ThemeStylesheetProvider implements BundleStylesheetProviderInterface
{
public function getStylesheets(): array
{
return [
'assets/styles/themes/ui.css',
'assets/styles/themes/site.css',
];
}
}
use c975L\UiBundle\Contract\BundleStylesheetManagementProviderInterface;
class StylesheetProvider implements BundleStylesheetManagementProviderInterface
{
public function getManagementStylesheets(): array
{
return [
'bundles/mybundle/css/management.min.css',
];
}
}
use c975L\UiBundle\Registry\StylesheetManagementRegistry;
public function __construct(
private readonly StylesheetManagementRegistry $stylesheetManagementRegistry,
) {}
public function configureAssets(): Assets
{
$assets = Assets::new();
foreach ($this->stylesheetManagementRegistry->all() as $stylesheet) {
$assets->addCssFile($stylesheet);
}
return $assets;
}
use c975L\UiBundle\Testing\ComponentCenteringAnalyzer;
use c975L\UiBundle\Testing\StylesheetCascade;
$analyzer = new ComponentCenteringAnalyzer(StylesheetCascade::fromFiles(
$uiBundleDir . '/public/css/styles.css', // load order matters: source order decides between two rules of equal specificity
$myBundleDir . '/public/css/styles.css',
));
foreach ($analyzer->analyse(ComponentCenteringAnalyzer::tagsByClass($myBundleDir . '/templates/components'))['violations'] as $violation) {
self::fail(ComponentCenteringAnalyzer::describe($violation));
}