diff --git a/app/bootstrap.php b/app/bootstrap.php
index af80becb..f12127c2 100644
--- a/app/bootstrap.php
+++ b/app/bootstrap.php
@@ -20,6 +20,7 @@ use Aura\Html\HelperLocatorFactory;
use Aura\Router\RouterContainer;
use Aura\Session\SessionFactory;
use Aviat\AnimeClient\API\{Anilist, Kitsu};
+use Aviat\AnimeClient\Component;
use Aviat\AnimeClient\Model;
use Aviat\Banker\Teller;
use Aviat\Ion\Config;
@@ -31,6 +32,9 @@ use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Psr\SimpleCache\CacheInterface;
+define('APP_DIR', __DIR__);
+define('TEMPLATE_DIR', APP_DIR . '/templates');
+
// -----------------------------------------------------------------------------
// Setup DI container
// -----------------------------------------------------------------------------
@@ -72,28 +76,45 @@ return static function (array $configArray = []): Container {
// Create Aura Router Object
$container->set('aura-router', fn() => new RouterContainer);
- // Create Html helper Object
+ // Create Html helpers
$container->set('html-helper', static function(ContainerInterface $container) {
$htmlHelper = (new HelperLocatorFactory)->newInstance();
- $htmlHelper->set('menu', static function() use ($container) {
- $menuHelper = new Helper\Menu();
- $menuHelper->setContainer($container);
- return $menuHelper;
- });
- $htmlHelper->set('field', static function() use ($container) {
- $formHelper = new Helper\Form();
- $formHelper->setContainer($container);
- return $formHelper;
- });
- $htmlHelper->set('picture', static function() use ($container) {
- $pictureHelper = new Helper\Picture();
- $pictureHelper->setContainer($container);
- return $pictureHelper;
- });
+ $helpers = [
+ 'menu' => Helper\Menu::class,
+ 'field' => Helper\Form::class,
+ 'picture' => Helper\Picture::class,
+ ];
+
+ foreach ($helpers as $name => $class)
+ {
+ $htmlHelper->set($name, static function() use ($class, $container) {
+ $helper = new $class;
+ $helper->setContainer($container);
+ return $helper;
+ });
+ }
return $htmlHelper;
});
+ // Create Component helpers
+ $container->set('component-helper', static function () {
+ $helper = (new HelperLocatorFactory)->newInstance();
+ $components = [
+ 'character' => Component\Character::class,
+ 'media' => Component\Media::class,
+ 'tabs' => Component\Tabs::class,
+ 'verticalTabs' => Component\VerticalTabs::class,
+ ];
+
+ foreach ($components as $name => $componentClass)
+ {
+ $helper->set($name, fn () => new $componentClass);
+ }
+
+ return $helper;
+ });
+
// Create Request Object
$container->set('request', fn () => ServerRequestFactory::fromGlobals(
$_SERVER,
diff --git a/app/templates/character.php b/app/templates/character.php
new file mode 100644
index 00000000..78e00795
--- /dev/null
+++ b/app/templates/character.php
@@ -0,0 +1,6 @@
+
+
+ = $picture ?>
+
\ No newline at end of file
diff --git a/app/templates/media.php b/app/templates/media.php
new file mode 100644
index 00000000..3cf7f25e
--- /dev/null
+++ b/app/templates/media.php
@@ -0,0 +1,12 @@
+
+ = $picture ?>
+
+
\ No newline at end of file
diff --git a/app/templates/tabs.php b/app/templates/tabs.php
new file mode 100644
index 00000000..17294e63
--- /dev/null
+++ b/app/templates/tabs.php
@@ -0,0 +1,23 @@
+
+ $tabData): ?>
+
+
+
+ />
+ = ucfirst($tabName) ?>
+
+ = $callback($tabData, $tabName) ?>
+
+
+
+
\ No newline at end of file
diff --git a/app/templates/vertical-tabs.php b/app/templates/vertical-tabs.php
new file mode 100644
index 00000000..72e3827f
--- /dev/null
+++ b/app/templates/vertical-tabs.php
@@ -0,0 +1,25 @@
+
+
+ $tabData): ?>
+
+
+
+ />
+ = $tabName ?>
+
+ = $callback($tabData, $tabName) ?>
+
+
+
+
+
\ No newline at end of file
diff --git a/app/views/anime/details.php b/app/views/anime/details.php
index 75a71eea..b6fa4150 100644
--- a/app/views/anime/details.php
+++ b/app/views/anime/details.php
@@ -1,9 +1,11 @@
-
+
= $helper->picture("images/anime/{$data['id']}-original.webp") ?>
@@ -115,81 +117,69 @@ use function Aviat\AnimeClient\getLocalImg;
-
Trailer
- VIDEO
+ Trailer
+ VIDEO
0): ?>
-
- Characters
+
+ Characters
-
-
- $list): ?>
-
/>
-
= ucfirst($role) ?>
-
-
-
-
-
+ = $component->tabs('character-types', $data['characters'], static function ($characterList, $role)
+ use ($component, $url, $helper) {
+ $rendered = [];
+ foreach ($characterList as $id => $character):
+ if (empty($character['image']['original']))
+ {
+ continue;
+ }
+ $rendered[] = $component->character(
+ $character['name'],
+ $url->generate('character', ['slug' => $character['slug']]),
+ $helper->picture("images/characters/{$id}.webp"),
+ (strtolower($role) !== 'main') ? 'small-character' : 'character'
+ );
+ endforeach;
+
+ return implode('', array_map('mb_trim', $rendered));
+ }) ?>
+
0): ?>
-
- Staff
+
+ = $component->verticalTabs('staff-role', $data['staff'], static function ($staffList)
+ use ($component, $url, $helper) {
+ $rendered = [];
+ foreach ($staffList as $id => $person):
+ if (empty($person['image']['original']))
+ {
+ continue;
+ }
+ $rendered[] = $component->character(
+ $person['name'],
+ $url->generate('person', ['id' => $person['id'], 'slug' => $person['slug']]),
+ $helper->picture(getLocalImg($person['image']['original'] ?? NULL)),
+ 'character small-person',
+ );
+ endforeach;
+
+ return implode('', array_map('mb_trim', $rendered));
+ }) ?>
+
\ No newline at end of file
diff --git a/app/views/character/details.php b/app/views/character/details.php
index 8d1b8a65..8e513f61 100644
--- a/app/views/character/details.php
+++ b/app/views/character/details.php
@@ -156,65 +156,50 @@ use Aviat\AnimeClient\API\Kitsu;
Voice Actors
-
-
+ = $component->tabs('character-vas', $vas, static function ($casting) use ($url, $component, $helper) {
+ $castings = [];
+ foreach ($casting as $id => $c):
+ $person = $component->character(
+ $c['person']['name'],
+ $url->generate('person', [
+ 'id' => $c['person']['id'],
+ 'slug' => $c['person']['slug']
+ ]),
+ $helper->picture(getLocalImg($c['person']['image']))
+ );
+ $medias = array_map(fn ($series) => $component->media(
+ array_merge([$series['title']], $series['titles']),
+ $url->generate('anime.details', ['id' => $series['slug']]),
+ $helper->picture(getLocalImg($series['posterImage'], TRUE))
+ ), $c['series']);
+ $media = implode('', array_map('mb_trim', $medias));
- $casting): ?>
-
type="radio" id="character-va= $i ?>"
- name="character-vas"
- />
-
= $language ?>
-
-
-
-
+ $castings[] = <<
+ {$person}
+
+
+
+
+HTML;
+ endforeach;
+
+ $languages = implode('', array_map('mb_trim', $castings));
+
+ return <<
+
+
+ Cast Member
+ Series
+
+
+ {$languages}
+
+HTML;
+ }, 'content') ?>
diff --git a/app/views/header.php b/app/views/header.php
index 25828f09..16fc6d55 100644
--- a/app/views/header.php
+++ b/app/views/header.php
@@ -26,7 +26,7 @@
-
+
\ No newline at end of file
diff --git a/console b/console
index a0999077..e499c9b1 100755
--- a/console
+++ b/console
@@ -9,6 +9,9 @@ use ConsoleKit\Console;
$_SERVER['HTTP_HOST'] = 'localhost';
+define('APP_DIR', __DIR__ . '/app');
+define('TEMPLATE_DIR', APP_DIR . '/templates');
+
// -----------------------------------------------------------------------------
// Start console script
// -----------------------------------------------------------------------------
diff --git a/frontEndSrc/css/src/general.css b/frontEndSrc/css/src/general.css
index 587e0582..29efb1f5 100644
--- a/frontEndSrc/css/src/general.css
+++ b/frontEndSrc/css/src/general.css
@@ -94,6 +94,7 @@ a:hover, a:active {
iframe {
display: block;
margin: 0 auto;
+ border: 0;
}
/* -----------------------------------------------------------------------------
diff --git a/src/AnimeClient/Component/Character.php b/src/AnimeClient/Component/Character.php
new file mode 100644
index 00000000..df64471b
--- /dev/null
+++ b/src/AnimeClient/Component/Character.php
@@ -0,0 +1,31 @@
+
+ * @copyright 2015 - 2020 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 5.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Component;
+
+final class Character {
+ use ComponentTrait;
+
+ public function __invoke(string $name, string $link, string $picture, string $className = 'character'): string
+ {
+ return $this->render('character.php', [
+ 'name' => $name,
+ 'link' => $link,
+ 'picture' => $picture,
+ 'className' => $className,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/AnimeClient/Component/ComponentTrait.php b/src/AnimeClient/Component/ComponentTrait.php
new file mode 100644
index 00000000..d4f909ae
--- /dev/null
+++ b/src/AnimeClient/Component/ComponentTrait.php
@@ -0,0 +1,30 @@
+
+ * @copyright 2015 - 2020 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 5.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Component;
+
+/**
+ * Shared logic for component-based functionality, like Tabs
+ */
+trait ComponentTrait {
+ public function render(string $path, array $data): string
+ {
+ ob_start();
+ extract($data, EXTR_OVERWRITE);
+ include \TEMPLATE_DIR . '/' .$path;
+ return ob_get_clean();
+ }
+}
\ No newline at end of file
diff --git a/src/AnimeClient/Component/Media.php b/src/AnimeClient/Component/Media.php
new file mode 100644
index 00000000..5da84759
--- /dev/null
+++ b/src/AnimeClient/Component/Media.php
@@ -0,0 +1,31 @@
+
+ * @copyright 2015 - 2020 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 5.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Component;
+
+final class Media {
+ use ComponentTrait;
+
+ public function __invoke(array $titles, string $link, string $picture, string $className = 'media'): string
+ {
+ return $this->render('media.php', [
+ 'titles' => $titles,
+ 'link' => $link,
+ 'picture' => $picture,
+ 'className' => $className,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/AnimeClient/Component/Tabs.php b/src/AnimeClient/Component/Tabs.php
new file mode 100644
index 00000000..91c9d572
--- /dev/null
+++ b/src/AnimeClient/Component/Tabs.php
@@ -0,0 +1,45 @@
+
+ * @copyright 2015 - 2020 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 5.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Component;
+
+final class Tabs {
+ use ComponentTrait;
+
+ /**
+ * Creates a tabbed content view
+ *
+ * @param string $name the name attribute for the input[type-option] form elements
+ * also used to generate id attributes
+ * @param array $tabData The data used to create the tab content, indexed by the tab label
+ * @param callable $cb The function to generate the tab content
+ * @return string
+ */
+ public function __invoke(
+ string $name,
+ array $tabData,
+ callable $cb,
+ string $className = 'content media-wrap flex flex-wrap flex-justify-start'
+ ): string
+ {
+ return $this->render('tabs.php', [
+ 'name' => $name,
+ 'data' => $tabData,
+ 'callback' => $cb,
+ 'className' => $className,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/AnimeClient/Component/VerticalTabs.php b/src/AnimeClient/Component/VerticalTabs.php
new file mode 100644
index 00000000..de05abf8
--- /dev/null
+++ b/src/AnimeClient/Component/VerticalTabs.php
@@ -0,0 +1,45 @@
+
+ * @copyright 2015 - 2020 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 5.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Component;
+
+final class VerticalTabs {
+ use ComponentTrait;
+
+ /**
+ * Creates a vertical tab content view
+ *
+ * @param string $name the name attribute for the input[type-option] form elements
+ * also used to generate id attributes
+ * @param array $tabData The data used to create the tab content, indexed by the tab label
+ * @param callable $cb The function to generate the tab content
+ * @return string
+ */
+ public function __invoke(
+ string $name,
+ array $tabData,
+ callable $cb,
+ string $className='content media-wrap flex flex-wrap flex-justify-start'
+ ): string
+ {
+ return $this->render('vertical-tabs.php', [
+ 'name' => $name,
+ 'data' => $tabData,
+ 'callback' => $cb,
+ 'className' => $className,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/AnimeClient/FormGenerator.php b/src/AnimeClient/FormGenerator.php
index 52873e24..94bbc28e 100644
--- a/src/AnimeClient/FormGenerator.php
+++ b/src/AnimeClient/FormGenerator.php
@@ -39,11 +39,30 @@ final class FormGenerator {
* @throws ContainerException
* @throws NotFoundException
*/
- public function __construct(ContainerInterface $container)
+ private function __construct(ContainerInterface $container)
{
$this->helper = $container->get('html-helper');
}
+ /**
+ * Create a new FormGenerator
+ *
+ * @param ContainerInterface $container
+ * @return $this
+ */
+ public static function new(ContainerInterface $container): self
+ {
+ try
+ {
+ return new static($container);
+ }
+ catch (\Throwable $e)
+ {
+ dump($e);
+ die();
+ }
+ }
+
/**
* Generate the html structure of the form
*
diff --git a/src/AnimeClient/Helper/Form.php b/src/AnimeClient/Helper/Form.php
index 7438a7f6..b1a60f93 100644
--- a/src/AnimeClient/Helper/Form.php
+++ b/src/AnimeClient/Helper/Form.php
@@ -35,6 +35,6 @@ final class Form {
*/
public function __invoke(string $name, array $form)
{
- return (new FormGenerator($this->container))->generate($name, $form);
+ return FormGenerator::new($this->container)->generate($name, $form);
}
}
diff --git a/src/AnimeClient/Helper/Menu.php b/src/AnimeClient/Helper/Menu.php
index 979892af..ad3fa263 100644
--- a/src/AnimeClient/Helper/Menu.php
+++ b/src/AnimeClient/Helper/Menu.php
@@ -34,8 +34,7 @@ final class Menu {
*/
public function __invoke($menuName)
{
- $generator = new MenuGenerator($this->container);
- return $generator->generate($menuName);
+ return MenuGenerator::new($this->container)->generate($menuName);
}
}
diff --git a/src/AnimeClient/MenuGenerator.php b/src/AnimeClient/MenuGenerator.php
index 87d8c411..65e5a98c 100644
--- a/src/AnimeClient/MenuGenerator.php
+++ b/src/AnimeClient/MenuGenerator.php
@@ -44,40 +44,20 @@ final class MenuGenerator extends UrlGenerator {
protected RequestInterface $request;
/**
- * MenuGenerator constructor.
- *
* @param ContainerInterface $container
- * @throws ContainerException
- * @throws NotFoundException
+ * @return static
*/
- public function __construct(ContainerInterface $container)
+ public static function new(ContainerInterface $container): self
{
- parent::__construct($container);
- $this->helper = $container->get('html-helper');
- $this->request = $container->get('request');
- }
-
- /**
- * Generate the full menu structure from the config files
- *
- * @param array $menus
- * @return array
- */
- protected function parseConfig(array $menus) : array
- {
- $parsed = [];
-
- foreach ($menus as $name => $menu)
+ try
{
- $parsed[$name] = [];
- foreach ($menu['items'] as $pathName => $partialPath)
- {
- $title = (string)StringType::from($pathName)->humanize()->titleize();
- $parsed[$name][$title] = (string)StringType::from($menu['route_prefix'])->append($partialPath);
- }
+ return new static($container);
+ }
+ catch (\Throwable $e)
+ {
+ dump($e);
+ die();
}
-
- return $parsed;
}
/**
@@ -120,5 +100,42 @@ final class MenuGenerator extends UrlGenerator {
// Create the menu html
return (string) $this->helper->ul();
}
+
+ /**
+ * MenuGenerator constructor.
+ *
+ * @param ContainerInterface $container
+ * @throws ContainerException
+ * @throws NotFoundException
+ */
+ private function __construct(ContainerInterface $container)
+ {
+ parent::__construct($container);
+ $this->helper = $container->get('html-helper');
+ $this->request = $container->get('request');
+ }
+
+ /**
+ * Generate the full menu structure from the config files
+ *
+ * @param array $menus
+ * @return array
+ */
+ private function parseConfig(array $menus) : array
+ {
+ $parsed = [];
+
+ foreach ($menus as $name => $menu)
+ {
+ $parsed[$name] = [];
+ foreach ($menu['items'] as $pathName => $partialPath)
+ {
+ $title = (string)StringType::from($pathName)->humanize()->titleize();
+ $parsed[$name][$title] = (string)StringType::from($menu['route_prefix'])->append($partialPath);
+ }
+ }
+
+ return $parsed;
+ }
}
// End of MenuGenerator.php
\ No newline at end of file
diff --git a/src/Ion/View/HtmlView.php b/src/Ion/View/HtmlView.php
index f7fcca05..e208ff45 100644
--- a/src/Ion/View/HtmlView.php
+++ b/src/Ion/View/HtmlView.php
@@ -16,7 +16,6 @@
namespace Aviat\Ion\View;
-use Aura\Html\HelperLocator;
use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Di\Exception\ContainerException;
@@ -30,13 +29,6 @@ use const EXTR_OVERWRITE;
class HtmlView extends HttpView {
use ContainerAware;
- /**
- * HTML generator/escaper helper
- *
- * @var HelperLocator
- */
- protected HelperLocator $helper;
-
/**
* Response mime type
*
@@ -56,7 +48,6 @@ class HtmlView extends HttpView {
parent::__construct();
$this->setContainer($container);
- $this->helper = $container->get('html-helper');
$this->response = new HtmlResponse('');
}
@@ -69,8 +60,10 @@ class HtmlView extends HttpView {
*/
public function renderTemplate(string $path, array $data): string
{
- $data['helper'] = $this->helper;
- $data['escape'] = $this->helper->escape();
+ $helper = $this->container->get('html-helper');
+ $data['component'] = $this->container->get('component-helper');
+ $data['helper'] = $helper;
+ $data['escape'] = $helper->escape();
$data['container'] = $this->container;
ob_start();