commit
6ff54c0791
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Schedule\SculpinScheduleBundle;
|
||||||
use App\Speakers\SculpinSpeakersBundle;
|
use App\Speakers\SculpinSpeakersBundle;
|
||||||
use Sculpin\Bundle\SculpinBundle\HttpKernel\AbstractKernel;
|
use Sculpin\Bundle\SculpinBundle\HttpKernel\AbstractKernel;
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ class SculpinKernel extends AbstractKernel
|
||||||
protected function getAdditionalSculpinBundles(): array
|
protected function getAdditionalSculpinBundles(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
SculpinScheduleBundle::class,
|
||||||
SculpinSpeakersBundle::class,
|
SculpinSpeakersBundle::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,66 @@ eventbrite:
|
||||||
papercall:
|
papercall:
|
||||||
url: https://www.papercall.io/drupalcamp-bristol-2019
|
url: https://www.papercall.io/drupalcamp-bristol-2019
|
||||||
|
|
||||||
|
schedule:
|
||||||
|
slots:
|
||||||
|
- id: 1
|
||||||
|
time: 8:30 am
|
||||||
|
label: Registration and refreshments
|
||||||
|
|
||||||
|
- id: 2
|
||||||
|
time: 9:00 am
|
||||||
|
label: Welcome
|
||||||
|
|
||||||
|
- id: 3
|
||||||
|
time: 9:10 am
|
||||||
|
|
||||||
|
- id: 4
|
||||||
|
time: 10:00 am
|
||||||
|
|
||||||
|
- id: 5
|
||||||
|
time: 10:30 am
|
||||||
|
label: Refreshments
|
||||||
|
|
||||||
|
- id: 6
|
||||||
|
time: 10:50 am
|
||||||
|
|
||||||
|
- id: 7
|
||||||
|
time: 11:40 am
|
||||||
|
|
||||||
|
- id: 8
|
||||||
|
time: 12:10 pm
|
||||||
|
label: Lunch
|
||||||
|
|
||||||
|
- id: 9
|
||||||
|
time: 1:10 pm
|
||||||
|
|
||||||
|
- id: 10
|
||||||
|
time: 2:00 pm
|
||||||
|
|
||||||
|
- id: 11
|
||||||
|
time: 2:15 pm
|
||||||
|
|
||||||
|
- id: 12
|
||||||
|
time: 2:30 pm
|
||||||
|
label: Refreshments
|
||||||
|
|
||||||
|
- id: 13
|
||||||
|
time: 2:50 pm
|
||||||
|
|
||||||
|
- id: 14
|
||||||
|
time: 3:05 pm
|
||||||
|
|
||||||
|
- id: 15
|
||||||
|
time: 3:20 pm
|
||||||
|
|
||||||
|
- id: 16
|
||||||
|
time: 4:10 pm
|
||||||
|
label: Closing remarks
|
||||||
|
|
||||||
|
- id: 17
|
||||||
|
time: 4:40 pm
|
||||||
|
label: Drinks reception
|
||||||
|
|
||||||
tickets:
|
tickets:
|
||||||
available: true
|
available: true
|
||||||
url: '%eventbrite.url%'
|
url: '%eventbrite.url%'
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"App\\Speakers\\": "src/Speakers/src"
|
"App\\Speakers\\": "src/Speakers/src",
|
||||||
|
"App\\Schedule\\": "src/Schedule/src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
|
|
|
@ -14,14 +14,14 @@
|
||||||
{
|
{
|
||||||
title: 'Speakers',
|
title: 'Speakers',
|
||||||
href: '/#speakers',
|
href: '/#speakers',
|
||||||
active: page.layout in ['session', 'speaker'],
|
active: page.layout == 'speaker',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Schedule',
|
title: 'Schedule',
|
||||||
href: '/schedule',
|
href: '/#schedule',
|
||||||
active: page.url == '/schedule' or page.layout in ['session', 'speaker'],
|
active: page.url == '/schedule' or page.layout == 'session',
|
||||||
enabled: false,
|
enabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Sponsor us',
|
title: 'Sponsor us',
|
||||||
|
|
22
source/_includes/schedule.html.twig
Normal file
22
source/_includes/schedule.html.twig
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<section id="schedule" class="tw-bg-purple-800 tw-text-white tw-py-16">
|
||||||
|
<div class="tw-max-w-xl tw-mx-auto tw-px-4 tw-text-center">
|
||||||
|
<h2 class="tw-text-3xl md:tw-text-4xl">The Schedule</h2>
|
||||||
|
|
||||||
|
<ul class="tw-list-reset tw-overflow-hidden">
|
||||||
|
{% for slot in slots %}
|
||||||
|
{% set session = sessionInSlot(slot.id, sessions) %}
|
||||||
|
<li class="tw-pt-4 lg:tw-pt-6 {{ loop.last ?: 'tw-pb-4 lg:tw-pb-6 tw-border-solid tw-border-0 tw-border-b tw-border-purple-400' }}">
|
||||||
|
<span class="tw-flex tw-items-center tw-justify-between tw--mx-6">
|
||||||
|
<span class="tw-px-6 tw-text-gray-200 tw-flex-1 tw-text-left">
|
||||||
|
<span class="tw-block">{{ session.title|default(slot.label)|default('TBA') }}</span>
|
||||||
|
{% if session.speakers %}
|
||||||
|
<span class="tw-block tw-mt-1">{{ session.speakers|join(', ') }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<span class="tw-px-6 tw-font-semibold">{{ slot.time }}</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Doing good with Drupal
|
title: Doing good with Drupal
|
||||||
speakers: [Matt Haworth]
|
speakers: [Matt Haworth]
|
||||||
|
slot: 15
|
||||||
use: [speakers]
|
use: [speakers]
|
||||||
---
|
---
|
||||||
More and more charities and campaigners are choosing Drupal to create websites that raise funds, find supporters and deliver content and services to those who need it most.
|
More and more charities and campaigners are choosing Drupal to create websites that raise funds, find supporters and deliver content and services to those who need it most.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
title: The Real State of Drupal
|
title: The Real State of Drupal
|
||||||
|
slot: 3
|
||||||
speakers: [Dan McNamara]
|
speakers: [Dan McNamara]
|
||||||
use: [speakers]
|
use: [speakers]
|
||||||
---
|
---
|
||||||
|
|
|
@ -3,7 +3,7 @@ layout: default
|
||||||
twitter:
|
twitter:
|
||||||
url: https://twitter.com/drupalcampbris
|
url: https://twitter.com/drupalcampbris
|
||||||
update_text: Early bird tickets are now available!
|
update_text: Early bird tickets are now available!
|
||||||
use: [speakers]
|
use: [sessions, speakers]
|
||||||
---
|
---
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main class="tw-bg-balloon tw-bg-center tw-bg-cover tw-flex tw-flex-col tw-flex-1">
|
<main class="tw-bg-balloon tw-bg-center tw-bg-cover tw-flex tw-flex-col tw-flex-1">
|
||||||
|
@ -43,4 +43,9 @@ use: [speakers]
|
||||||
{% include 'front-speakers' with {
|
{% include 'front-speakers' with {
|
||||||
speakers: data.speakers,
|
speakers: data.speakers,
|
||||||
} %}
|
} %}
|
||||||
|
|
||||||
|
{% include 'schedule' with {
|
||||||
|
sessions: data.sessions,
|
||||||
|
slots: site.schedule.slots,
|
||||||
|
} %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
layout: page
|
|
||||||
title: Schedule
|
|
||||||
use:
|
|
||||||
- sessions
|
|
||||||
---
|
|
||||||
<ul>
|
|
||||||
{% for session in data.sessions %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ session.url }}">{{ session.title }}</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
4
src/Schedule/services.yml
Normal file
4
src/Schedule/services.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
services:
|
||||||
|
App\Schedule\TwigExtension\ScheduleExtension:
|
||||||
|
tags:
|
||||||
|
- { name: twig.extension }
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Schedule\DependencyInjection;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
|
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||||
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
|
||||||
|
class SculpinScheduleExtension extends Extension
|
||||||
|
{
|
||||||
|
public function load(array $configs, ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../../'));
|
||||||
|
$loader->load('services.yml');
|
||||||
|
}
|
||||||
|
}
|
30
src/Schedule/src/Model/Session.php
Normal file
30
src/Schedule/src/Model/Session.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Schedule\Model;
|
||||||
|
|
||||||
|
use Tightenco\Collect\Support\Collection;
|
||||||
|
|
||||||
|
class Session
|
||||||
|
{
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
public function __construct($data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSlot(): int
|
||||||
|
{
|
||||||
|
return (int) $this->data['slot'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->data['title'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSpeakers(): Collection
|
||||||
|
{
|
||||||
|
return collect($this->data['speakers']);
|
||||||
|
}
|
||||||
|
}
|
9
src/Schedule/src/SculpinScheduleBundle.php
Normal file
9
src/Schedule/src/SculpinScheduleBundle.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Schedule;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
|
||||||
|
class SculpinScheduleBundle extends Bundle
|
||||||
|
{
|
||||||
|
}
|
29
src/Schedule/src/TwigExtension/ScheduleExtension.php
Normal file
29
src/Schedule/src/TwigExtension/ScheduleExtension.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Schedule\TwigExtension;
|
||||||
|
|
||||||
|
use App\Schedule\Model\Session;
|
||||||
|
use Twig\Extension\AbstractExtension;
|
||||||
|
use Twig\TwigFunction;
|
||||||
|
|
||||||
|
class ScheduleExtension extends AbstractExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getFunctions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFunction('sessionInSlot', [$this, 'getSessionInSlot']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSessionInSlot(int $slotId, array $sessions): ?Session
|
||||||
|
{
|
||||||
|
return collect($sessions)->map(function ($session): ?Session {
|
||||||
|
return new Session($session);
|
||||||
|
})->first(function (?Session $session) use ($slotId): bool {
|
||||||
|
return $session->getSlot() == $slotId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
38
src/Schedule/tests/ScheduleTest.php
Normal file
38
src/Schedule/tests/ScheduleTest.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tests\Schedule;
|
||||||
|
|
||||||
|
use App\Schedule\Model\Session;
|
||||||
|
use App\Schedule\TwigExtension\ScheduleExtension;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ScheduleTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \App\Schedule\TwigExtension\ScheduleExtension
|
||||||
|
*/
|
||||||
|
private $extension;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->extension = new ScheduleExtension();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function get_a_session_for_a_slot()
|
||||||
|
{
|
||||||
|
$sessions = [
|
||||||
|
['title' => 'The Real State of Drupal', 'slot' => 4],
|
||||||
|
['title' => 'Using Ansible for automation', 'slot' => 1],
|
||||||
|
['title' => 'Introduction to Views', 'slot' => 3],
|
||||||
|
['title' => 'Doing Good with Drupal', 'slot' => 2],
|
||||||
|
];
|
||||||
|
|
||||||
|
$session = $this->extension->getSessionInSlot(3, $sessions);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Session::class, $session);
|
||||||
|
$this->assertSame('Introduction to Views', $session->getTitle());
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,9 +28,12 @@ class SpeakersExtension extends AbstractExtension
|
||||||
*/
|
*/
|
||||||
public function getSessionSpeakers($session, array $speakers): array
|
public function getSessionSpeakers($session, array $speakers): array
|
||||||
{
|
{
|
||||||
return collect($speakers)->filter(function ($speaker) use ($session): bool {
|
return collect($speakers)
|
||||||
return collect($session['speakers'])->contains($speaker['title']);
|
->filter(function ($speaker) use ($session): bool {
|
||||||
})->values()->toArray();
|
return collect($session['speakers'])->contains($speaker['title']);
|
||||||
|
})
|
||||||
|
->values()
|
||||||
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,8 +46,11 @@ class SpeakersExtension extends AbstractExtension
|
||||||
*/
|
*/
|
||||||
public function getSpeakerSessions($speaker, array $sessions): array
|
public function getSpeakerSessions($speaker, array $sessions): array
|
||||||
{
|
{
|
||||||
return collect($sessions)->filter(function ($session) use ($speaker): bool {
|
return collect($sessions)
|
||||||
return collect($session['speakers'])->contains($speaker['title']);
|
->filter(function ($session) use ($speaker): bool {
|
||||||
})->values()->toArray();
|
return collect($session['speakers'])->contains($speaker['title']);
|
||||||
|
})
|
||||||
|
->values()
|
||||||
|
->toArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue