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
use App\Schedule\SculpinScheduleBundle;
use App\Speakers\SculpinSpeakersBundle;
use Sculpin\Bundle\SculpinBundle\HttpKernel\AbstractKernel;
@ -8,6 +9,7 @@ class SculpinKernel extends AbstractKernel
protected function getAdditionalSculpinBundles(): array
{
return [
SculpinScheduleBundle::class,
SculpinSpeakersBundle::class,
];
}

View file

@ -12,6 +12,66 @@ eventbrite:
papercall:
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:
available: true
url: '%eventbrite.url%'

View file

@ -33,7 +33,8 @@
},
"autoload": {
"psr-4": {
"App\\Speakers\\": "src/Speakers/src"
"App\\Speakers\\": "src/Speakers/src",
"App\\Schedule\\": "src/Schedule/src"
}
},
"autoload-dev": {

View file

@ -14,14 +14,14 @@
{
title: 'Speakers',
href: '/#speakers',
active: page.layout in ['session', 'speaker'],
active: page.layout == 'speaker',
enabled: true,
},
{
title: 'Schedule',
href: '/schedule',
active: page.url == '/schedule' or page.layout in ['session', 'speaker'],
enabled: false,
href: '/#schedule',
active: page.url == '/schedule' or page.layout == 'session',
enabled: true,
},
{
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
speakers: [Matt Haworth]
slot: 15
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.

View file

@ -1,5 +1,6 @@
---
title: The Real State of Drupal
slot: 3
speakers: [Dan McNamara]
use: [speakers]
---

View file

@ -3,7 +3,7 @@ layout: default
twitter:
url: https://twitter.com/drupalcampbris
update_text: Early bird tickets are now available!
use: [speakers]
use: [sessions, speakers]
---
{% block content %}
<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 {
speakers: data.speakers,
} %}
{% include 'schedule' with {
sessions: data.sessions,
slots: site.schedule.slots,
} %}
{% 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
{
return collect($speakers)->filter(function ($speaker) use ($session): bool {
return collect($session['speakers'])->contains($speaker['title']);
})->values()->toArray();
return collect($speakers)
->filter(function ($speaker) use ($session): bool {
return collect($session['speakers'])->contains($speaker['title']);
})
->values()
->toArray();
}
/**
@ -43,8 +46,11 @@ class SpeakersExtension extends AbstractExtension
*/
public function getSpeakerSessions($speaker, array $sessions): array
{
return collect($sessions)->filter(function ($session) use ($speaker): bool {
return collect($session['speakers'])->contains($speaker['title']);
})->values()->toArray();
return collect($sessions)
->filter(function ($session) use ($speaker): bool {
return collect($session['speakers'])->contains($speaker['title']);
})
->values()
->toArray();
}
}