Skip to content

Commit dd9b402

Browse files
committed
[Site] new facet menu demo WIP
1 parent 4523fce commit dd9b402

File tree

11 files changed

+1258
-0
lines changed

11 files changed

+1258
-0
lines changed

ux.symfony.com/src/Controller/Demo/LiveDemoController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public function invoice(LiveDemoRepository $liveDemoRepository, ?Invoice $invoic
9393
}
9494

9595
#[Route('/{demo}', name: 'app_demo_live_component_demo')]
96+
#[Route('/animalz', name: 'app_demo_live_component_animalz')]
9697
#[Route('/auto-validating-form', name: 'app_demo_live_component_auto_validating_form')]
9798
#[Route('/chartjs', name: 'app_demo_live_component_chartjs')]
9899
#[Route('/dependent-form-fields', name: 'app_demo_live_component_dependent_form_fields')]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace App\Enum;
15+
16+
enum AnimalzType: string
17+
{
18+
case Normal = 'NORMAL';
19+
case Water = 'WATER';
20+
case Flying = 'FLYING';
21+
case Bug = 'BUG';
22+
case Fight = 'FIGHT';
23+
case Dark = 'DARK';
24+
case Poison = 'POISON';
25+
case Grass = 'GRASS';
26+
case Fairy = 'FAIRY';
27+
case Fossil = 'FOSSIL';
28+
29+
public function getColor(): string
30+
{
31+
return match ($this) {
32+
self::Normal => '#9fa19f',
33+
self::Water => '#2980ef',
34+
self::Flying => '#81b9ef',
35+
self::Bug => '#91a119',
36+
self::Fight => '#ff8100',
37+
self::Dark => '#4f3f3d',
38+
self::Poison => '#9141cb',
39+
self::Grass => '#3fa129',
40+
self::Fairy => '#ef70ef',
41+
self::Fossil => '#5060e1',
42+
};
43+
}
44+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace App\Model;
13+
14+
use App\Enum\AnimalzType;
15+
16+
final class Animalz
17+
{
18+
/**
19+
* @param list<string> $type
20+
*/
21+
public function __construct(
22+
private string $name,
23+
private array $type,
24+
private int $legs,
25+
private string $description,
26+
) {
27+
}
28+
29+
public function getName(): string
30+
{
31+
return $this->name;
32+
}
33+
34+
/**
35+
* @return list<string>
36+
*/
37+
public function getType(): array
38+
{
39+
return $this->type;
40+
}
41+
42+
public function hasType(string $type): bool
43+
{
44+
return \in_array($type, $this->type, true);
45+
}
46+
47+
public function getLegs(): int
48+
{
49+
return $this->legs;
50+
}
51+
52+
public function getDescription(): string
53+
{
54+
return $this->description;
55+
}
56+
57+
/**
58+
* @return list<string>
59+
*/
60+
public function getTypeColors(): array
61+
{
62+
return array_map(
63+
static fn (string $type): string => AnimalzType::tryFrom($type)?->getColor() ?? '#6c757d',
64+
$this->type,
65+
);
66+
}
67+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace App\Service;
13+
14+
use App\Enum\AnimalzType;
15+
use App\Model\Animalz;
16+
17+
class AnimalzRepository
18+
{
19+
private const string DATA_FILE = __DIR__.'/data/animalz-properties.json';
20+
21+
/** @var list<Animalz>|null */
22+
private ?array $zanimalz = null;
23+
24+
/**
25+
* @return list<Animalz>
26+
*/
27+
public function findAll(): array
28+
{
29+
return $this->zanimalz ??= $this->loadZanimalz();
30+
}
31+
32+
/**
33+
* @return list<Animalz>
34+
*/
35+
public function findByNameAndTypeAndLegs(?string $name, ?AnimalzType $type, ?int $maxLegs): array
36+
{
37+
$zanimalz = $this->findAll();
38+
39+
if (null !== $name && '' !== $name) {
40+
$zanimalz = array_filter(
41+
$zanimalz,
42+
fn (Animalz $animalz): bool => str_contains(
43+
strtolower($animalz->getName()),
44+
strtolower($name),
45+
),
46+
);
47+
}
48+
49+
if (null !== $type) {
50+
$zanimalz = array_filter(
51+
$zanimalz,
52+
fn (Animalz $animalz): bool => $animalz->hasType($type->value),
53+
);
54+
}
55+
56+
if (null !== $maxLegs) {
57+
$zanimalz = array_filter(
58+
$zanimalz,
59+
fn (Animalz $animalz): bool => $animalz->getLegs() <= $maxLegs,
60+
);
61+
}
62+
63+
$zanimalz = array_values($zanimalz);
64+
usort($zanimalz, fn (Animalz $a, Animalz $b): int => $a->getName() <=> $b->getName());
65+
66+
return $zanimalz;
67+
}
68+
69+
public function getMaxLegs(): int
70+
{
71+
$zanimalz = $this->findAll();
72+
73+
return max(array_map(fn (Animalz $a): int => $a->getLegs(), $zanimalz));
74+
}
75+
76+
/**
77+
* @return list<Animalz>
78+
*/
79+
private function loadZanimalz(): array
80+
{
81+
$content = file_get_contents(self::DATA_FILE);
82+
83+
if (false === $content) {
84+
return [];
85+
}
86+
87+
$data = json_decode($content, true, 512, \JSON_THROW_ON_ERROR);
88+
89+
return array_map(
90+
fn (array $item): Animalz => new Animalz($item['name'], $item['type'], $item['legs'], $item['description']),
91+
$data,
92+
);
93+
}
94+
}

ux.symfony.com/src/Service/LiveDemoRepository.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ class LiveDemoRepository
2121
public function findAll(): array
2222
{
2323
return [
24+
new LiveDemo(
25+
identifier: 'animalz',
26+
name: 'Facet Filtering',
27+
description: 'Filter results based on a facet menu, with URL parameters.',
28+
author: 'Nayte',
29+
publishedAt: '2025-12-12',
30+
tags: ['facets', 'filter', 'LiveAction'],
31+
longDescription: <<<'EOF'
32+
This demo showcases faceted search with two Live Components working together.
33+
34+
Filter a list of animals by their **number of legs**, **weight**, or **natural habitat** using a dynamic facet menu that updates the results in real time.
35+
EOF,
36+
),
2437
new LiveDemo(
2538
'infinite-scroll-2',
2639
name: 'Infinite Scroll - 2/2',

0 commit comments

Comments
 (0)