added tiles

This commit is contained in:
Tim Lappe 2025-05-27 18:58:31 +02:00
parent a331d1a8da
commit 593972c401
52 changed files with 851 additions and 97 deletions

View File

@ -14,7 +14,6 @@ RUN apk add --no-cache \
autoconf \
g++ \
make \
zsh \
wget
# Install PHP extensions
@ -27,11 +26,5 @@ RUN pecl install mongodb \
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Install Oh My Zsh
RUN sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
# Set zsh as default shell
RUN chsh -s $(which zsh)
# CMD will be executed when container starts
CMD ["php", "-S", "0.0.0.0:3000", "-t", "public"]

58
docs/SubSectionTile.md Normal file
View File

@ -0,0 +1,58 @@
# SubSectionTile
The `SubSectionTile` allows you to group similar tiles together within a section, providing better organization and visual hierarchy.
## Usage
```php
use App\Domain\Search\Tiles\SubSectionTile;
// Create a sub-section with grouped tiles
$performanceSubSection = new SubSectionTile(
'Performance', // Title
[ // Array of tiles
new PowerTile(new Power(210)),
new AccelerationTile(new Acceleration(6.6)),
new TopSpeedTile(new TopSpeed(180)),
new DrivetrainTile(new Drivetrain('rear')),
],
'Motor and driving performance specifications' // Optional description
);
```
## Parameters
- **`title`** (string): The title of the sub-section
- **`tiles`** (array): Array of tile objects to group together
- **`description`** (string, optional): Optional description text displayed below the title
## Example
```php
new SectionTile('Skoda Elroq 85', [
new BrandTile('Skoda'),
new PriceTile(new Price(43900, Currency::euro())),
new SubSectionTile('Performance', [
new PowerTile(new Power(210)),
new AccelerationTile(new Acceleration(6.6)),
new TopSpeedTile(new TopSpeed(180)),
new DrivetrainTile(new Drivetrain('rear')),
], 'Motor and driving performance specifications'),
new SubSectionTile('Range & Efficiency', [
new RangeTile(new Range(450)),
new BatteryTile(new Battery(77.0, 82.0)),
new ConsumptionTile(new Consumption(171)),
new ChargingTile(new ChargingSpeed(175, 11)),
], 'Battery capacity, range, and charging capabilities'),
]);
```
## Visual Hierarchy
- **Section**: Large heading (h1) with prominent styling
- **Sub-section**: Medium heading (h2) with subtle styling
- **Tiles**: Individual data tiles within each sub-section
The sub-section provides a clear visual separation between different categories of information while maintaining the overall design consistency.

View File

@ -19,6 +19,6 @@ class TileTwigName extends AbstractExtension
public function twigName(object $tile): string
{
return (new \ReflectionClass($tile))->getShortName();
return str_replace('tile', '', strtolower((new \ReflectionClass($tile))->getShortName()));
}
}

View File

@ -2,16 +2,16 @@
namespace App\Domain\Model;
class Brand
final readonly class Brand
{
public function __construct(
public private(set) readonly string $id,
public private(set) readonly string $name,
public private(set) readonly string $logo,
public private(set) readonly string $description,
public private(set) readonly int $foundedYear,
public private(set) readonly string $headquarters,
public private(set) readonly string $website,
public private(set) readonly array $carModels,
public readonly string $id,
public readonly string $name,
public readonly string $logo,
public readonly string $description,
public readonly int $foundedYear,
public readonly string $headquarters,
public readonly string $website,
public readonly array $carModels,
) {}
}

View File

@ -2,33 +2,29 @@
namespace App\Domain\Model;
class CarRevision
use App\Domain\Model\Value\Acceleration;
use App\Domain\Model\Value\Battery;
use App\Domain\Model\Value\Consumption;
use App\Domain\Model\Value\ChargingSpeed;
use App\Domain\Model\Value\Power;
use App\Domain\Model\Value\Range;
use App\Domain\Model\Value\TopSpeed;
use App\Domain\Model\Value\Price;
final readonly class CarRevision
{
private ?string $id = null;
private string $name;
private int $releaseYear;
private array $engineTypes = [];
private ?int $horsePower = null;
private ?int $torque = null;
private ?int $topSpeed = null;
private ?float $accelerationZeroToHundred = null;
private ?int $range = null;
private ?float $batteryCapacity = null;
private ?int $chargingTime = null;
private ?float $consumption = null;
private ?float $price = null;
private ?CarModel $carModel = null;
public function __construct(
public string $name,
public int $releaseYear,
public ?Power $power = null,
public ?Acceleration $acceleration = null,
public ?TopSpeed $topSpeed = null,
public ?Range $range = null,
public ?Battery $battery = null,
public ?Consumption $consumption = null,
public ?Price $price = null,
public ?ChargingSpeed $chargingSpeed = null,
public ?CarModel $carModel = null,
public ?Image $image = null,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Model;
final readonly class Image
{
public function __construct(
public ?string $externalPublicUrl = null,
public ?string $relativePublicUrl = null,
) {
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Domain\Model\Value;
class Acceleration
{
public function __construct(
public readonly float $secondsFrom0To100,
) {
}
public function __toString(): string
{
return $this->secondsFrom0To100 . ' sec (0-100 km/h)';
}
public function getSeconds(): float
{
return $this->secondsFrom0To100;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Domain\Model\Value;
class Battery
{
public function __construct(
public readonly Energy $usableCapacity,
public readonly Energy $totalCapacity,
public readonly string $technology = 'Lithium-Ion',
) {
}
public function __toString(): string
{
return $this->usableCapacity->__toString();
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Domain\Model\Value;
class ChargingSpeed
{
public function __construct(
public readonly Power $dcMaxKw,
public readonly Power $acMaxKw,
) {
}
public function __toString(): string
{
return $this->dcMax() . ' DC / ' . $this->acMax() . ' AC';
}
public function dcMax(): Power
{
return $this->dcMaxKw;
}
public function acMax(): Power
{
return $this->acMaxKw;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Domain\Model\Value;
class Consumption
{
public function __construct(
public readonly Energy $energyPerKm,
) {
}
public function __toString(): string
{
return $this->energyPerKm->kwh() . ' kWh/100km';
}
public function energyPerKm(): Energy
{
return $this->energyPerKm;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Domain\Model\Value;
class Currency
{
public function __construct(
public readonly string $symbol = '€',
public readonly string $currency = 'EUR',
public readonly string $name = 'Euro',
) {}
public function __toString(): string
{
return $this->symbol;
}
public function symbol(): string
{
return $this->symbol;
}
public function currency(): string
{
return $this->currency;
}
public function name(): string
{
return $this->name;
}
public static function euro(): self
{
return new self('€', 'EUR', 'Euro');
}
public static function usd(): self
{
return new self('$', 'USD', 'US Dollar');
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Domain\Model\Value;
class Drivetrain
{
public function __construct(
public readonly string $type,
) {
}
public function __toString(): string
{
return match($this->type) {
'rear' => 'Heckantrieb',
'front' => 'Frontantrieb',
'awd' => 'Allradantrieb',
default => $this->type,
};
}
public function getType(): string
{
return $this->type;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Domain\Model\Value;
class Energy
{
public function __construct(
private readonly float $kwh,
) {
}
public function __toString(): string
{
return $this->kwh . ' kWh';
}
public function kwh(): float
{
return $this->kwh;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Domain\Model\Value;
class Power
{
public function __construct(
public readonly float $kilowatts,
) {
}
public function __toString(): string
{
return $this->kilowatts . ' kW';
}
public function kilowatts(): float
{
return $this->kilowatts;
}
public function horsePower(): int
{
return (int) round($this->kilowatts * 1.36);
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Domain\Model\Value;
class Price
{
public function __construct(
public readonly int $price,
public readonly Currency $currency,
) {}
public function __toString(): string
{
return number_format($this->price, 0, ',', '.') . ' ' . $this->currency->symbol();
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Domain\Model\Value;
class Range
{
public function __construct(
public readonly int $kilometers,
) {
}
public function __toString(): string
{
return $this->kilometers . ' km';
}
public function rangeInKm(): int
{
return $this->kilometers;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Domain\Model\Value;
class TopSpeed
{
public function __construct(
public readonly int $kmh,
) {
}
public function __toString(): string
{
return $this->kmh . ' km/h';
}
public function getKmh(): int
{
return $this->kmh;
}
}

View File

@ -2,16 +2,72 @@
namespace App\Domain\Search;
use App\Domain\Search\Tiles\Section;
use App\Domain\Search\Tiles\Brand;
use App\Domain\Model\CarRevision;
use App\Domain\Model\Image;
use App\Domain\Model\Value\Currency;
use App\Domain\Model\Value\Price;
use App\Domain\Model\Value\Range;
use App\Domain\Model\Value\Battery;
use App\Domain\Model\Value\Power;
use App\Domain\Model\Value\Acceleration;
use App\Domain\Model\Value\ChargingSpeed;
use App\Domain\Model\Value\Consumption;
use App\Domain\Model\Value\TopSpeed;
use App\Domain\Model\Value\Drivetrain;
use App\Domain\Model\Value\Energy;
use App\Domain\Search\Tiles\SectionTile;
use App\Domain\Search\Tiles\SubSectionTile;
use App\Domain\Search\Tiles\BrandTile;
use App\Domain\Search\Tiles\PriceTile;
use App\Domain\Search\Tiles\RangeTile;
use App\Domain\Search\Tiles\BatteryTile;
use App\Domain\Search\Tiles\PowerTile;
use App\Domain\Search\Tiles\AccelerationTile;
use App\Domain\Search\Tiles\ChargingTile;
use App\Domain\Search\Tiles\ConsumptionTile;
use App\Domain\Search\Tiles\AvailabilityTile;
use App\Domain\Search\Tiles\CarTile;
use App\Domain\Search\Tiles\TopSpeedTile;
use App\Domain\Search\Tiles\DrivetrainTile;
class Engine
{
public function search(string $query): TileCollection
{
$skodaElroq85 = new CarRevision(
'Skoda Elroq 85', 2024,
new Power(210),
new Acceleration(6.6),
new TopSpeed(180),
new Range(450),
new Battery(new Energy(77.0), new Energy(82.0)),
new Consumption(new Energy(171)),
new Price(43900, Currency::euro()),
new ChargingSpeed(new Power(175), new Power(11)),
image: new Image('https://www.scherer-gruppe.de/media/f3b72d42-4b26-4606-8df4-d840efeff017/01_elroc.jpg?w=1920&h=758&action=crop&scale=both&anchor=middlecenter'),
);
return new TileCollection([
new Section('Hello', [
new Brand('Tesla', 'https://www.tesla.com/tesla_theme/assets/img/meta-tags/apple-touch-icon.png'),
new SectionTile('Skoda Elroq 85', [
new CarTile($skodaElroq85->image, [
new BrandTile('Skoda'),
new PriceTile(new Price(43900, Currency::euro())),
new AvailabilityTile('Bestellbar', 'Oktober 2024'),
new RangeTile(new Range(450)),
]),
new SubSectionTile('Performance', [
new PowerTile(new Power(210)),
new AccelerationTile(new Acceleration(6.6)),
new TopSpeedTile(new TopSpeed(180)),
new DrivetrainTile(new Drivetrain('rear')),
], 'Motor and driving performance specifications'),
new SubSectionTile('Range & Efficiency', [
new RangeTile(new Range(450)),
new BatteryTile(new Battery(new Energy(77.0), new Energy(82.0))),
new ConsumptionTile(new Consumption(new Energy(171))),
new ChargingTile(new ChargingSpeed(new Power(175), new Power(11))),
], 'Battery capacity, range, and charging capabilities'),
]),
]);
}

View File

@ -2,7 +2,7 @@
namespace App\Domain\Search;
use App\Domain\Search\Tiles\Section;
use App\Domain\Search\Tiles\SectionTile;
class TileCollection
{

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\Acceleration;
class AccelerationTile
{
public function __construct(
public readonly Acceleration $acceleration,
) {}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Domain\Search\Tiles;
class AvailabilityTile
{
public function __construct(
public readonly string $status,
public readonly ?string $availableSince = null,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\Battery;
class BatteryTile
{
public function __construct(
public readonly Battery $battery,
) {}
}

View File

@ -2,10 +2,10 @@
namespace App\Domain\Search\Tiles;
class Brand
class BrandTile
{
public function __construct(
public readonly string $name,
public readonly string $logo,
public readonly ?string $logo = null,
) {}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Image;
final readonly class CarTile
{
public function __construct(
public Image $image,
public array $tiles
) { }
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\ChargingSpeed;
class ChargingTile
{
public function __construct(
public readonly ChargingSpeed $chargingSpeed,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\Consumption;
class ConsumptionTile
{
public function __construct(
public readonly Consumption $consumption,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\Drivetrain;
class DrivetrainTile
{
public function __construct(
public readonly Drivetrain $drivetrain,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\Power;
class PowerTile
{
public function __construct(
public readonly Power $power,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\Price;
class PriceTile
{
public function __construct(
public readonly Price $price,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\Range;
class RangeTile
{
public function __construct(
public readonly Range $range,
) {}
}

View File

@ -2,7 +2,7 @@
namespace App\Domain\Search\Tiles;
class Section
class SectionTile
{
public function __construct(
public readonly string $title,

View File

@ -0,0 +1,11 @@
<?php
namespace App\Domain\Search\Tiles;
class SubSectionTile
{
public function __construct(
public readonly string $title,
public readonly array $tiles,
) {}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Domain\Search\Tiles;
use App\Domain\Model\Value\TopSpeed;
class TopSpeedTile
{
public function __construct(
public readonly TopSpeed $topSpeed,
) {}
}

View File

@ -7,11 +7,7 @@ use MongoDB\Database;
class MongoDBClient
{
public private(set) Client $client;
public Database $database {
get => $this->client->selectDatabase($this->databaseName);
}
private Client $client;
public function __construct(
private readonly string $dsl,
@ -19,4 +15,14 @@ class MongoDBClient
) {
$this->client = new Client($this->dsl);
}
public function getClient(): Client
{
return $this->client;
}
public function getDatabase(): Database
{
return $this->client->selectDatabase($this->databaseName);
}
}

View File

@ -15,7 +15,7 @@ final class MongoDBBrandRepository implements BrandRepository
public function findAll(): BrandCollection
{
$result = $this->client->database->selectCollection('brands')->find();
$result = $this->client->getDatabase()->selectCollection('brands')->find();
$brands = [];
$mapper = new ModelMapper();

View File

@ -26,25 +26,25 @@
}
.header {
text-align: center;
margin-bottom: 3rem;
display: flex;
justify-content: stretch;
gap: 2rem;
align-items: center;
margin-bottom: 2.5rem;
}
.title {
font-size: 3.5rem;
font-size: 2.5rem;
font-weight: 800;
margin-bottom: 2.5rem;
letter-spacing: -1px;
background: linear-gradient(90deg, #083d77 0%, #2e4057 35%, #d1495b 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
display: inline-block;
}
.search-container {
max-width: 600px;
margin: 0 auto 3rem;
flex-grow: 1;
position: relative;
}
@ -55,9 +55,12 @@
border: 2px solid #e0e0e0;
border-radius: 50px;
outline: none;
transition: all 0.3s ease;
transition: all 0.1s ease;
background: white;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.search-input:hover {
border-color: #083d77;
}
.search-input:focus {
@ -68,8 +71,7 @@
.search-button {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
top: 8px;
background: #083d77;
color: white;
border: none;
@ -84,30 +86,109 @@
background: #2e4057;
}
.tile {
/* Tiles Grid Layout */
.tiles-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1px;
padding: 0;
overflow: hidden;
}
.tile-wrapper {
display: flex;
border-radius: 10px;
padding: 10px;
background-color: #fff;
flex-direction: column;
height: 100%;
position: relative;
}
/* Special handling for subsection tiles */
.tile-wrapper:has(.subsection) {
grid-column: 1 / -1;
min-height: auto;
}
.tile {
background: white;
border: none;
border-radius: 0;
padding: 1.5rem;
width: 100%;
height: 100%;
min-height: 120px;
display: flex;
flex-direction: column;
justify-content: space-between;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
flex: 1;
}
.tile::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #083d77, #2e4057, #d1495b);
opacity: 0;
transition: opacity 0.3s ease;
}
.tile:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(8, 61, 119, 0.15);
background: rgba(8, 61, 119, 0.02);
z-index: 1;
cursor: pointer;
}
.tile:hover::before {
opacity: 1;
}
.tile-title {
font-size: 1.2rem;
font-weight: 600;
font-size: 1.25rem;
font-weight: 700;
color: #083d77;
margin-bottom: 0.5rem;
line-height: 1.3;
}
.tile-container {
.tile-subtitle {
font-size: 0.9rem;
color: #666;
margin-bottom: 0.75rem;
font-weight: 500;
}
.tile small {
font-size: 0.75rem;
color: #888;
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
margin-top: auto;
}
.tile-logo {
width: 40px;
height: 40px;
object-fit: contain;
margin-bottom: 1rem;
border-radius: 8px;
background: rgba(8, 61, 119, 0.05);
padding: 0.5rem;
}
.tile-content {
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 0.5rem;
}
.tile-container > * {
flex-grow: 0;
flex-shrink: 1;
justify-content: flex-start;
}
.results-container {
@ -115,12 +196,69 @@
}
.section-title {
font-size: 1.5rem;
font-weight: 700;
font-size: 1.75rem;
font-weight: 800;
color: #083d77;
margin-bottom: 1rem;
border-bottom: 2px solid #e0e0e0;
margin: 2.5rem 0 1.5rem 0;
padding-bottom: 0.5rem;
border-bottom: 2px solid rgba(8, 61, 119, 0.1);
position: relative;
}
.section-title::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 60px;
height: 2px;
background: linear-gradient(90deg, #083d77, #d1495b);
}
.section-title:first-child {
margin-top: 0;
}
.section-tiles-container {
margin-bottom: 2rem;
}
.subsection {
margin-top: 1rem;
}
.subsection-title {
font-size: 1.1rem;
font-weight: 600;
padding: 0.25rem 0.5rem;
position: relative;
border-radius: 2px 2px 0 0;
border-bottom: none;
display: inline-block;
min-width: 120px;
z-index: 1;
width: 100%;
margin-top: 1.5rem;
}
.subsection-description {
font-size: 0.9rem;
margin: 0;
padding: 0.25rem 1rem 0.75rem;
font-style: italic;
background: rgba(255, 255, 255, 0.8);
border: 1px solid rgba(224, 224, 224, 0.5);
border-top: none;
border-bottom: none;
margin-left: 0;
}
.subsection-tiles-container {
background: transparent;
border: none;
border-radius: 0;
overflow: visible;
margin-top: 0rem;
}
.loading {
@ -145,8 +283,38 @@
padding: 1rem;
}
.brands-grid {
.tiles-grid {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1px;
}
.tile-wrapper {
min-height: 100px;
}
.tile {
padding: 1.25rem;
min-height: 100px;
}
.tile-title {
font-size: 1.1rem;
}
}
@media (max-width: 480px) {
.tiles-grid {
grid-template-columns: 1fr;
gap: 1px;
}
.tile-wrapper {
min-height: 80px;
}
.tile {
padding: 1rem;
min-height: 80px;
}
}
</style>

View File

@ -7,5 +7,7 @@
{% include '_components/search.html.twig' with { query: query } %}
</div>
{% include 'result/tiles/collection.html.twig' with { tiles: tiles } %}
<div class="tiles-grid">
{% include 'result/tiles/collection.html.twig' with { tiles: tiles } %}
</div>
{% endblock %}

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.acceleration }}</div>
<small>Beschleunigung</small>
</div>

View File

@ -0,0 +1,9 @@
<div class="tile">
<div class="tile-content">
<div class="tile-title">{{ tile.status }}</div>
{% if tile.availableSince %}
<div class="tile-subtitle">seit {{ tile.availableSince }}</div>
{% endif %}
</div>
<small>Verfügbarkeit</small>
</div>

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.battery }}</div>
<small>Batterie</small>
</div>

View File

@ -1,4 +1,9 @@
<div class="tile">
<img src="{{ tile.logo }}" alt="{{ tile.name }}" class="tile-logo">
<div class="tile-title">{{ tile.name }}</div>
{% if tile.logo %}
<img src="{{ tile.logo }}" alt="{{ tile.name }}" class="tile-logo">
{% endif %}
<div class="tile-content">
<div class="tile-title">{{ tile.name }}</div>
</div>
<small>Marke</small>
</div>

View File

@ -0,0 +1,8 @@
<div style="grid-column: span 2; grid-row: span 4;">
{% if tile.image %}
<img src="{{ tile.image.externalPublicUrl }}" style="width: 100%; height: 100%; object-fit: cover;">
{% endif %}
</div>
{% for tile in tile.tiles %}
{{ include('result/tiles/' ~ tile|twig_name ~ '.html.twig', { tile: tile }) }}
{% endfor %}

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.chargingSpeed }}</div>
<small>Laden</small>
</div>

View File

@ -1,5 +1,3 @@
{% for tile in tiles %}
<div class="tile-container">
{% include 'result/tiles/' ~ tile|twig_name ~ '.html.twig' with { tile: tile } %}
</div>
{% include 'result/tiles/' ~ tile|twig_name ~ '.html.twig' with { tile: tile } %}
{% endfor %}

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.consumption }}</div>
<small>Verbrauch</small>
</div>

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.drivetrain }}</div>
<small>Antrieb</small>
</div>

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.power }}</div>
<small>Leistung</small>
</div>

View File

@ -0,0 +1,6 @@
<div class="tile">
<div class="tile-content">
<div class="tile-title">{{ tile.price }}</div>
</div>
<small>Preis</small>
</div>

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.range }}</div>
<small>Reichweite</small>
</div>

View File

@ -1,3 +1,3 @@
<h1>{{ tile.title }}</h1>
<h1 class="section-title" style="grid-column: span 4;">{{ tile.title }}</h1>
{% include 'result/tiles/collection.html.twig' with { tiles: tile.tiles } %}

View File

@ -0,0 +1,2 @@
<h2 class="subsection-title" style="grid-column: span 4">{{ tile.title }}</h2>
{% include 'result/tiles/collection.html.twig' with { tiles: tile.tiles } %}

View File

@ -0,0 +1,4 @@
<div class="tile">
<div class="tile-title">{{ tile.topSpeed }}</div>
<small>Höchstgeschwindigkeit</small>
</div>