Merge pull request #10 from opdavies/schedule

Add schedule
This commit is contained in:
Oliver Davies 2019-05-23 01:20:17 +01:00 committed by GitHub
commit 6ff54c0791
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 237 additions and 25 deletions

View file

@ -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,
]; ];
} }

View file

@ -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%'

View file

@ -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": {

View file

@ -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',

View 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>

View file

@ -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.

View file

@ -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]
--- ---

View file

@ -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 %}

View file

@ -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>

View file

@ -0,0 +1,4 @@
services:
App\Schedule\TwigExtension\ScheduleExtension:
tags:
- { name: twig.extension }

View file

@ -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');
}
}

View 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']);
}
}

View file

@ -0,0 +1,9 @@
<?php
namespace App\Schedule;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class SculpinScheduleBundle extends Bundle
{
}

View 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;
});
}
}

View 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());
}
}

View file

@ -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)
->filter(function ($speaker) use ($session): bool {
return collect($session['speakers'])->contains($speaker['title']); return collect($session['speakers'])->contains($speaker['title']);
})->values()->toArray(); })
->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)
->filter(function ($session) use ($speaker): bool {
return collect($session['speakers'])->contains($speaker['title']); return collect($session['speakers'])->contains($speaker['title']);
})->values()->toArray(); })
->values()
->toArray();
} }
} }