diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index fed484c9..df0c8a6e 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -17,9 +17,9 @@ Javascript dependencies: - [rollup](https://rollupjs.org/) ([MIT License](https://github.com/rollup/rollup/blob/master/LICENSE.md)) - [tailwindcss](https://tailwindcss.com/) ([MIT License](https://github.com/tailwindcss/tailwindcss/blob/master/LICENSE)) -- [CodeMirror](https://github.com/codemirror/CodeMirror) ([MIT License](https://github.com/codemirror/CodeMirror/blob/master/LICENSE)) - [ProseMirror](https://prosemirror.net/) ([MIT License](https://github.com/ProseMirror/prosemirror/blob/master/LICENSE)) - [D3: Data-Driven Documents](https://d3js.org) ([BSD 3-Clause "New" or "Revised" License](https://github.com/d3/d3/blob/master/LICENSE)) +- [Choices.js](https://joshuajohnson.co.uk/Choices/) ([MIT License](https://github.com/jshjohnson/Choices/blob/master/LICENSE)) Other: diff --git a/app/Config/Pager.php b/app/Config/Pager.php index 50a4a5f9..699ab907 100644 --- a/app/Config/Pager.php +++ b/app/Config/Pager.php @@ -20,7 +20,7 @@ class Pager extends BaseConfig | */ public $templates = [ - 'default_full' => 'CodeIgniter\Pager\Views\default_full', + 'default_full' => 'App\Views\pager\default_full', 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 'default_head' => 'CodeIgniter\Pager\Views\default_head', ]; diff --git a/app/Controllers/Admin/BaseController.php b/app/Controllers/Admin/BaseController.php index 92f4849a..5d7de7d2 100644 --- a/app/Controllers/Admin/BaseController.php +++ b/app/Controllers/Admin/BaseController.php @@ -26,7 +26,7 @@ class BaseController extends Controller * * @var array */ - protected $helpers = ['auth', 'breadcrumb', 'svg']; + protected $helpers = ['auth', 'breadcrumb', 'svg', 'components']; /** * Constructor. diff --git a/app/Controllers/Admin/Contributor.php b/app/Controllers/Admin/Contributor.php index 693746d0..01e66ee6 100644 --- a/app/Controllers/Admin/Contributor.php +++ b/app/Controllers/Admin/Contributor.php @@ -166,7 +166,7 @@ class Contributor extends BaseController public function remove() { - if ($this->podcast->owner_id == $this->user->id) { + if ($this->podcast->created_by == $this->user->id) { return redirect() ->back() ->with('errors', [ diff --git a/app/Controllers/Admin/Episode.php b/app/Controllers/Admin/Episode.php index 39ce2e0c..5e25bd00 100644 --- a/app/Controllers/Admin/Episode.php +++ b/app/Controllers/Admin/Episode.php @@ -45,8 +45,14 @@ class Episode extends BaseController public function list() { + $episodes = (new EpisodeModel()) + ->where('podcast_id', $this->podcast->id) + ->orderBy('created_at', 'desc'); + $data = [ 'podcast' => $this->podcast, + 'episodes' => $episodes->paginate(10), + 'pager' => $episodes->pager, ]; replace_breadcrumb_params([ @@ -57,7 +63,10 @@ class Episode extends BaseController public function view() { - $data = ['episode' => $this->episode]; + $data = [ + 'podcast' => $this->podcast, + 'episode' => $this->episode, + ]; replace_breadcrumb_params([ 0 => $this->podcast->title, @@ -105,7 +114,10 @@ class Episode extends BaseController 'enclosure' => $this->request->getFile('enclosure'), 'description' => $this->request->getPost('description'), 'image' => $this->request->getFile('image'), - 'explicit' => $this->request->getPost('explicit') == 'yes', + 'parental_advisory' => + $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null, 'number' => $this->request->getPost('episode_number'), 'season_number' => $this->request->getPost('season_number'), 'type' => $this->request->getPost('type'), @@ -120,14 +132,33 @@ class Episode extends BaseController $episodeModel = new EpisodeModel(); - if (!$episodeModel->save($newEpisode)) { + if (!($newEpisodeId = $episodeModel->insert($newEpisode, true))) { return redirect() ->back() ->withInput() ->with('errors', $episodeModel->errors()); } - return redirect()->route('episode-list', [$this->podcast->id]); + // update podcast's episode_description_footer if changed + $podcastModel = new PodcastModel(); + + if ($this->podcast->hasChanged('episode_description_footer')) { + $this->podcast->episode_description_footer = $this->request->getPost( + 'description_footer' + ); + + if (!$podcastModel->update($this->podcast->id, $this->podcast)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + } + + return redirect()->route('episode-view', [ + $this->podcast->id, + $newEpisodeId, + ]); } public function edit() @@ -135,6 +166,7 @@ class Episode extends BaseController helper(['form']); $data = [ + 'podcast' => $this->podcast, 'episode' => $this->episode, ]; @@ -167,7 +199,10 @@ class Episode extends BaseController $this->episode->title = $this->request->getPost('title'); $this->episode->slug = $this->request->getPost('slug'); $this->episode->description = $this->request->getPost('description'); - $this->episode->explicit = $this->request->getPost('explicit') == 'yes'; + $this->episode->parental_advisory = + $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null; $this->episode->number = $this->request->getPost('episode_number'); $this->episode->season_number = $this->request->getPost('season_number') ? $this->request->getPost('season_number') @@ -191,14 +226,32 @@ class Episode extends BaseController $episodeModel = new EpisodeModel(); - if (!$episodeModel->save($this->episode)) { + if (!$episodeModel->update($this->episode->id, $this->episode)) { return redirect() ->back() ->withInput() ->with('errors', $episodeModel->errors()); } - return redirect()->route('episode-list', [$this->podcast->id]); + // update podcast's episode_description_footer if changed + $this->podcast->episode_description_footer = $this->request->getPost( + 'description_footer' + ); + + if ($this->podcast->hasChanged('episode_description_footer')) { + $podcastModel = new PodcastModel(); + if (!$podcastModel->update($this->podcast->id, $this->podcast)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $podcastModel->errors()); + } + } + + return redirect()->route('episode-view', [ + $this->podcast->id, + $this->episode->id, + ]); } public function delete() diff --git a/app/Controllers/Admin/Myaccount.php b/app/Controllers/Admin/Myaccount.php index 7a058af0..50f2fb45 100644 --- a/app/Controllers/Admin/Myaccount.php +++ b/app/Controllers/Admin/Myaccount.php @@ -57,9 +57,8 @@ class MyAccount extends BaseController } user()->password = $this->request->getPost('new_password'); - $userModel->save(user()); - if (!$userModel->save(user())) { + if (!$userModel->update(user()->id, user())) { return redirect() ->back() ->withInput() diff --git a/app/Controllers/Admin/Page.php b/app/Controllers/Admin/Page.php index 384b72bf..f2ce56db 100644 --- a/app/Controllers/Admin/Page.php +++ b/app/Controllers/Admin/Page.php @@ -59,7 +59,7 @@ class Page extends BaseController $pageModel = new PageModel(); - if (!$pageModel->save($page)) { + if (!$pageModel->insert($page)) { return redirect() ->back() ->withInput() @@ -92,7 +92,7 @@ class Page extends BaseController $pageModel = new PageModel(); - if (!$pageModel->save($this->page)) { + if (!$pageModel->update($this->page->id, $this->page)) { return redirect() ->back() ->withInput() diff --git a/app/Controllers/Admin/Podcast.php b/app/Controllers/Admin/Podcast.php index ab0dde47..794bcef3 100644 --- a/app/Controllers/Admin/Podcast.php +++ b/app/Controllers/Admin/Podcast.php @@ -94,21 +94,20 @@ class Podcast extends BaseController 'title' => $this->request->getPost('title'), 'name' => $this->request->getPost('name'), 'description' => $this->request->getPost('description'), - 'episode_description_footer' => $this->request->getPost( - 'episode_description_footer' - ), 'image' => $this->request->getFile('image'), 'language' => $this->request->getPost('language'), 'category_id' => $this->request->getPost('category'), - 'explicit' => $this->request->getPost('explicit') == 'yes', - 'author' => $this->request->getPost('author'), + 'parental_advisory' => + $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null, 'owner_name' => $this->request->getPost('owner_name'), 'owner_email' => $this->request->getPost('owner_email'), + 'publisher' => $this->request->getPost('publisher'), 'type' => $this->request->getPost('type'), 'copyright' => $this->request->getPost('copyright'), - 'block' => $this->request->getPost('block') == 'yes', - 'complete' => $this->request->getPost('complete') == 'yes', - 'custom_html_head' => $this->request->getPost('custom_html_head'), + 'block' => $this->request->getPost('block') === 'yes', + 'complete' => $this->request->getPost('complete') === 'yes', 'created_by' => user(), 'updated_by' => user(), ]); @@ -119,7 +118,7 @@ class Podcast extends BaseController $db->transStart(); if (!($newPodcastId = $podcastModel->insert($podcast, true))) { - $db->transComplete(); + $db->transRollback(); return redirect() ->back() ->withInput() @@ -135,6 +134,12 @@ class Podcast extends BaseController $podcastAdminGroup->id ); + // set Podcast categories + (new CategoryModel())->setPodcastCategories( + $newPodcastId, + $this->request->getPost('other_categories') + ); + $db->transComplete(); return redirect()->route('podcast-view', [$newPodcastId]); @@ -205,20 +210,22 @@ class Podcast extends BaseController 'image' => download_file($nsItunes->image->attributes()), 'language' => $this->request->getPost('language'), 'category_id' => $this->request->getPost('category'), - 'explicit' => empty($nsItunes->explicit) - ? false - : $nsItunes->explicit == 'yes', - 'author' => $nsItunes->author, + 'parental_advisory' => empty($nsItunes->explicit) + ? null + : (in_array($nsItunes->explicit, ['yes', 'true']) + ? 'explicit' + : null), 'owner_name' => $nsItunes->owner->name, 'owner_email' => $nsItunes->owner->email, + 'publisher' => $nsItunes->author, 'type' => empty($nsItunes->type) ? 'episodic' : $nsItunes->type, 'copyright' => $feed->channel[0]->copyright, 'block' => empty($nsItunes->block) ? false - : $nsItunes->block == 'yes', + : $nsItunes->block === 'yes', 'complete' => empty($nsItunes->complete) ? false - : $nsItunes->complete == 'yes', + : $nsItunes->complete === 'yes', 'created_by' => user(), 'updated_by' => user(), ]); @@ -229,7 +236,7 @@ class Podcast extends BaseController $db->transStart(); if (!($newPodcastId = $podcastModel->insert($podcast, true))) { - $db->transComplete(); + $db->transRollback(); return redirect() ->back() ->withInput() @@ -265,7 +272,7 @@ class Podcast extends BaseController ); $slug = slugify( - $this->request->getPost('slug_field') == 'title' + $this->request->getPost('slug_field') === 'title' ? $item->title : basename($item->link) ); @@ -285,22 +292,23 @@ class Podcast extends BaseController 'slug' => $slug, 'enclosure' => download_file($item->enclosure->attributes()), 'description' => $converter->convert( - $this->request->getPost('description_field') == 'summary' + $this->request->getPost('description_field') === 'summary' ? $nsItunes->summary - : ($this->request->getPost('description_field') == + : ($this->request->getPost('description_field') === 'subtitle_summary' - ? '

' . - $nsItunes->subtitle . - "

\n" . - $nsItunes->summary + ? $nsItunes->subtitle . "\n" . $nsItunes->summary : $item->description) ), 'image' => empty($nsItunes->image->attributes()) ? null : download_file($nsItunes->image->attributes()), - 'explicit' => $nsItunes->explicit == 'yes', + 'explicit' => $nsItunes->explicit + ? (in_array($nsItunes->explicit, ['yes', 'true']) + ? 'explicit' + : null) + : null, 'number' => - $this->request->getPost('force_renumber') == 'yes' + $this->request->getPost('force_renumber') === 'yes' ? $itemNumber : $nsItunes->episode, 'season_number' => empty( @@ -313,7 +321,7 @@ class Podcast extends BaseController : $nsItunes->episodeType, 'block' => empty($nsItunes->block) ? false - : $nsItunes->block == 'yes', + : $nsItunes->block === 'yes', 'created_by' => user(), 'updated_by' => user(), ]); @@ -324,8 +332,8 @@ class Podcast extends BaseController $episodeModel = new EpisodeModel(); - if (!$episodeModel->save($newEpisode)) { - // FIX: What shall we do? + if (!$episodeModel->insert($newEpisode)) { + // FIXME: What shall we do? return redirect() ->back() ->withInput() @@ -335,7 +343,7 @@ class Podcast extends BaseController $db->transComplete(); - return redirect()->route('podcast-list'); + return redirect()->route('podcast-view', [$newPodcastId]); } public function edit() @@ -372,9 +380,6 @@ class Podcast extends BaseController $this->podcast->title = $this->request->getPost('title'); $this->podcast->name = $this->request->getPost('name'); $this->podcast->description = $this->request->getPost('description'); - $this->podcast->episode_description_footer = $this->request->getPost( - 'episode_description_footer' - ); $image = $this->request->getFile('image'); if ($image->isValid()) { @@ -382,29 +387,50 @@ class Podcast extends BaseController } $this->podcast->language = $this->request->getPost('language'); $this->podcast->category_id = $this->request->getPost('category'); - $this->podcast->explicit = $this->request->getPost('explicit') == 'yes'; - $this->podcast->author = $this->request->getPost('author'); + $this->podcast->parental_advisory = + $this->request->getPost('parental_advisory') !== 'undefined' + ? $this->request->getPost('parental_advisory') + : null; + $this->podcast->publisher = $this->request->getPost('publisher'); $this->podcast->owner_name = $this->request->getPost('owner_name'); $this->podcast->owner_email = $this->request->getPost('owner_email'); $this->podcast->type = $this->request->getPost('type'); $this->podcast->copyright = $this->request->getPost('copyright'); - $this->podcast->block = $this->request->getPost('block') == 'yes'; - $this->podcast->complete = $this->request->getPost('complete') == 'yes'; - $this->podcast->custom_html_head = $this->request->getPost( - 'custom_html_head' - ); + $this->podcast->block = $this->request->getPost('block') === 'yes'; + $this->podcast->complete = + $this->request->getPost('complete') === 'yes'; $this->updated_by = user(); - $podcastModel = new PodcastModel(); + $db = \Config\Database::connect(); + $db->transStart(); - if (!$podcastModel->save($this->podcast)) { + $podcastModel = new PodcastModel(); + if (!$podcastModel->update($this->podcast->id, $this->podcast)) { + $db->transRollback(); return redirect() ->back() ->withInput() ->with('errors', $podcastModel->errors()); } - return redirect()->route('podcast-list'); + // set Podcast categories + (new CategoryModel())->setPodcastCategories( + $this->podcast->id, + $this->request->getPost('other_categories') + ); + + $db->transComplete(); + + return redirect()->route('podcast-view', [$this->podcast->id]); + } + + public function latestEpisodes(int $limit) + { + $episodes = (new EpisodeModel()) + ->orderBy('created_at', 'desc') + ->findAll($limit); + + return view('admin/podcast/latest_episodes', ['episodes' => $episodes]); } public function delete() diff --git a/app/Controllers/Admin/User.php b/app/Controllers/Admin/User.php index 63874156..be174529 100644 --- a/app/Controllers/Admin/User.php +++ b/app/Controllers/Admin/User.php @@ -86,7 +86,7 @@ class User extends BaseController // Force user to reset his password on first connection $user->forcePasswordReset(); - if (!$userModel->save($user)) { + if (!$userModel->insert($user)) { return redirect() ->back() ->withInput() @@ -150,7 +150,7 @@ class User extends BaseController $userModel = new UserModel(); $this->user->forcePasswordReset(); - if (!$userModel->save($this->user)) { + if (!$userModel->update($this->user->id, $this->user)) { return redirect() ->back() ->with('errors', $userModel->errors()); @@ -184,7 +184,7 @@ class User extends BaseController // TODO: add ban reason? $this->user->ban(''); - if (!$userModel->save($this->user)) { + if (!$userModel->update($this->user->id, $this->user)) { return redirect() ->back() ->with('errors', $userModel->errors()); @@ -205,7 +205,7 @@ class User extends BaseController $userModel = new UserModel(); $this->user->unBan(); - if (!$userModel->save($this->user)) { + if (!$userModel->update($this->user->id, $this->user)) { return redirect() ->back() ->with('errors', $userModel->errors()); diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index aaac73cc..1a36daf1 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -12,6 +12,14 @@ use App\Entities\User; class Auth extends \Myth\Auth\Controllers\AuthController { + /** + * An array of helpers to be automatically loaded + * upon class instantiation. + * + * @var array + */ + protected $helpers = ['components']; + /** * Attempt to register a new user. */ diff --git a/app/Controllers/BaseController.php b/app/Controllers/BaseController.php index ab5eef7d..2f5bdcff 100644 --- a/app/Controllers/BaseController.php +++ b/app/Controllers/BaseController.php @@ -26,7 +26,7 @@ class BaseController extends Controller * * @var array */ - protected $helpers = ['analytics', 'svg']; + protected $helpers = ['analytics', 'svg', 'components']; /** * Constructor. diff --git a/app/Controllers/Episode.php b/app/Controllers/Episode.php index a0e0dfa2..8b340901 100644 --- a/app/Controllers/Episode.php +++ b/app/Controllers/Episode.php @@ -57,6 +57,7 @@ class Episode extends BaseController $data = [ 'previousEpisode' => $previousNextEpisodes['previous'], 'nextEpisode' => $previousNextEpisodes['next'], + 'podcast' => $this->podcast, 'episode' => $this->episode, ]; diff --git a/app/Database/Migrations/2020-05-30-101500_add_podcasts.php b/app/Database/Migrations/2020-05-30-101500_add_podcasts.php index 4c024439..a95e4db1 100644 --- a/app/Database/Migrations/2020-05-30-101500_add_podcasts.php +++ b/app/Database/Migrations/2020-05-30-101500_add_podcasts.php @@ -50,10 +50,11 @@ class AddPodcasts extends Migration 'unsigned' => true, 'default' => 0, ], - 'explicit' => [ - 'type' => 'TINYINT', - 'constraint' => 1, - 'default' => 0, + 'parental_advisory' => [ + 'type' => 'ENUM', + 'constraint' => ['clean', 'explicit'], + 'null' => true, + 'default' => null, ], 'owner_name' => [ 'type' => 'VARCHAR', @@ -63,7 +64,7 @@ class AddPodcasts extends Migration 'type' => 'VARCHAR', 'constraint' => 1024, ], - 'author' => [ + 'publisher' => [ 'type' => 'VARCHAR', 'constraint' => 1024, 'null' => true, @@ -92,10 +93,6 @@ class AddPodcasts extends Migration 'type' => 'TEXT', 'null' => true, ], - 'custom_html_head' => [ - 'type' => 'TEXT', - 'null' => true, - ], 'created_by' => [ 'type' => 'INT', 'constraint' => 11, diff --git a/app/Database/Migrations/2020-06-05-170000_add_episodes.php b/app/Database/Migrations/2020-06-05-170000_add_episodes.php index e965fd8e..24b2f02f 100644 --- a/app/Database/Migrations/2020-06-05-170000_add_episodes.php +++ b/app/Database/Migrations/2020-06-05-170000_add_episodes.php @@ -70,10 +70,11 @@ class AddEpisodes extends Migration 'constraint' => 1024, 'null' => true, ], - 'explicit' => [ - 'type' => 'TINYINT', - 'constraint' => 1, - 'default' => 0, + 'parental_advisory' => [ + 'type' => 'ENUM', + 'constraint' => ['clean', 'explicit'], + 'null' => true, + 'default' => null, ], 'number' => [ 'type' => 'INT', diff --git a/app/Database/Migrations/2020-09-29-150000_add_podcasts_categories.php b/app/Database/Migrations/2020-09-29-150000_add_podcasts_categories.php new file mode 100644 index 00000000..4139b150 --- /dev/null +++ b/app/Database/Migrations/2020-09-29-150000_add_podcasts_categories.php @@ -0,0 +1,42 @@ +forge->addField([ + 'podcast_id' => [ + 'type' => 'BIGINT', + 'constraint' => 20, + 'unsigned' => true, + ], + 'category_id' => [ + 'type' => 'INT', + 'constraint' => 10, + 'unsigned' => true, + ], + ]); + $this->forge->addPrimaryKey(['podcast_id', 'category_id']); + $this->forge->addForeignKey('podcast_id', 'podcasts', 'id'); + $this->forge->addForeignKey('category_id', 'categories', 'id'); + $this->forge->createTable('podcasts_categories'); + } + + public function down() + { + $this->forge->dropTable('podcasts_categories'); + } +} diff --git a/app/Entities/Episode.php b/app/Entities/Episode.php index 9c731123..7bbda5e5 100644 --- a/app/Entities/Episode.php +++ b/app/Entities/Episode.php @@ -66,7 +66,7 @@ class Episode extends Entity 'enclosure_filesize' => 'integer', 'description' => 'string', 'image_uri' => '?string', - 'explicit' => 'boolean', + 'parental_advisory' => '?string', 'number' => '?integer', 'season_number' => '?integer', 'type' => 'string', diff --git a/app/Entities/Podcast.php b/app/Entities/Podcast.php index 0a8a273b..c0dd2b7d 100644 --- a/app/Entities/Podcast.php +++ b/app/Entities/Podcast.php @@ -37,6 +37,16 @@ class Podcast extends Entity */ protected $category; + /** + * @var \App\Entities\Category[] + */ + protected $other_categories; + + /** + * @var integer[] + */ + protected $other_categories_ids; + /** * @var \App\Entities\User[] */ @@ -60,8 +70,8 @@ class Podcast extends Entity 'image_uri' => 'string', 'language' => 'string', 'category_id' => 'integer', - 'explicit' => 'boolean', - 'author' => '?string', + 'parental_advisory' => '?string', + 'publisher' => '?string', 'owner_name' => '?string', 'owner_email' => '?string', 'type' => 'string', @@ -69,7 +79,6 @@ class Podcast extends Entity 'block' => 'boolean', 'complete' => 'boolean', 'episode_description_footer' => '?string', - 'custom_html_head' => '?string', 'created_by' => 'integer', 'updated_by' => 'integer', 'imported_feed_url' => '?string', @@ -225,4 +234,33 @@ class Podcast extends Entity return $this->platforms; } + + public function getOtherCategories() + { + if (empty($this->id)) { + throw new \RuntimeException( + 'Podcast must be created before getting other categories.' + ); + } + + if (empty($this->other_categories)) { + $this->other_categories = (new CategoryModel())->getPodcastCategories( + $this->id + ); + } + + return $this->other_categories; + } + + public function getOtherCategoriesIds() + { + if (empty($this->other_categories_ids)) { + $this->other_categories_ids = array_column( + $this->getOtherCategories(), + 'id' + ); + } + + return $this->other_categories_ids; + } } diff --git a/app/Entities/User.php b/app/Entities/User.php index ed6bc920..6a3e7a1f 100644 --- a/app/Entities/User.php +++ b/app/Entities/User.php @@ -1,5 +1,11 @@ render(); + return $breadcrumb->render($class); } function replace_breadcrumb_params($newParams) diff --git a/app/Helpers/components_helper.php b/app/Helpers/components_helper.php new file mode 100644 index 00000000..5b26da6d --- /dev/null +++ b/app/Helpers/components_helper.php @@ -0,0 +1,258 @@ + 'default', + 'size' => 'base', + 'iconLeft' => null, + 'iconRight' => null, + 'isRoundedFull' => false, + 'isSquared' => false, + ]; + $options = array_merge($defaultOptions, $customOptions); + + $baseClass = + 'inline-flex items-center shadow-xs outline-none focus:shadow-outline'; + + $variantClass = [ + 'default' => 'bg-gray-300 hover:bg-gray-400', + 'primary' => 'text-white bg-green-500 hover:bg-green-600', + 'secondary' => 'text-white bg-gray-700 hover:bg-gray-800', + 'success' => 'text-white bg-green-600 hover:bg-green-700', + 'danger' => 'text-white bg-red-600 hover:bg-red-700', + 'warning' => 'text-black bg-yellow-500 hover:bg-yellow-600', + 'info' => 'text-white bg-teal-500 hover:bg-teal-600', + ]; + + $sizeClass = [ + 'small' => 'text-xs md:text-sm ', + 'base' => 'text-sm md:text-base', + 'large' => 'text-lg md:text-xl', + ]; + + $basePaddings = [ + 'small' => 'px-1 md:px-2 md:py-1', + 'base' => 'px-2 py-1 md:px-3 md:py-2', + 'large' => 'px-3 py-2 md:px-4 md:py-2', + ]; + + $squaredPaddings = [ + 'small' => 'p-1', + 'base' => 'p-2', + 'large' => 'p-3', + ]; + + $roundedClass = [ + 'full' => 'rounded-full', + 'small' => 'rounded-sm md:rounded', + 'base' => 'rounded md:rounded-md', + 'large' => 'rounded-md md:rounded-lg', + ]; + + $buttonClass = + $baseClass . + ' ' . + ($options['isRoundedFull'] + ? $roundedClass['full'] + : $roundedClass[$options['size']]) . + ' ' . + ($options['isSquared'] + ? $squaredPaddings[$options['size']] + : $basePaddings[$options['size']]) . + ' ' . + $sizeClass[$options['size']] . + ' ' . + $variantClass[$options['variant']]; + + if (!empty($customAttributes['class'])) { + $buttonClass .= ' ' . $customAttributes['class']; + unset($customAttributes['class']); + } + + if ($options['iconLeft']) { + $label = icon($options['iconLeft'], 'mr-2') . $label; + } + + if ($options['iconRight']) { + $label .= icon($options['iconRight'], 'ml-2'); + } + + if ($uri) { + return anchor( + $uri, + $label, + array_merge( + [ + 'class' => $buttonClass, + ], + $customAttributes + ) + ); + } + + $defaultButtonAttributes = [ + 'type' => 'button', + ]; + $attributes = array_merge($defaultButtonAttributes, $customAttributes); + + return ''; + } +} + +// ------------------------------------------------------------------------ + +if (!function_exists('icon_button')) { + /** + * Icon Button component + * + * Abstracts the `button()` helper to create a stylized icon button + * + * @param string $label The button label + * @param mixed|null $uri URI string or array of URI segments + * @param array $customOptions button options: variant, size, iconLeft, iconRight + * @param array $customAttributes Additional attributes + * + * @return string + */ + function icon_button( + string $icon, + string $title, + $uri = null, + $customOptions = [], + $customAttributes = [] + ): string { + $defaultOptions = [ + 'isRoundedFull' => true, + 'isSquared' => true, + ]; + $options = array_merge($defaultOptions, $customOptions); + + $defaultAttributes = [ + 'title' => $title, + 'data-toggle' => 'tooltip', + 'data-placement' => 'bottom', + ]; + $attributes = array_merge($defaultAttributes, $customAttributes); + + return button(icon($icon), $uri, $options, $attributes); + } +} + +// ------------------------------------------------------------------------ + +if (!function_exists('hint_tooltip')) { + /** + * Hint component + * + * Used to produce tooltip with a question mark icon for hint texts + * + * @param string $hintText The hint text + * + * @return string + */ + function hint_tooltip(string $hintText = '', string $class = ''): string + { + $tooltip = + '' . icon('question') . ''; + } +} + +// ------------------------------------------------------------------------ + +if (!function_exists('data_table')) { + /** + * Data table component + * + * Creates a stylized table. + * + * @param array $columns array of associate arrays with `header` and `cell` keys where `cell` is a function with a row of $data as parameter + * @param array $data data to loop through and display in rows + * @param array ...$rest Any other argument to pass to the `cell` function + * + * @return string + */ + function data_table($columns, $data = [], ...$rest): string + { + $table = new \CodeIgniter\View\Table(); + + $template = [ + 'table_open' => '', + + 'thead_open' => + '', + + 'heading_cell_start' => '', + 'row_alt_start' => '', + ]; + + $table->setTemplate($template); + + $tableHeaders = []; + foreach ($columns as $column) { + array_push($tableHeaders, $column['header']); + } + + $table->setHeading($tableHeaders); + + if ($dataCount = count($data)) { + for ($i = 0; $i < $dataCount; $i++) { + $row = $data[$i]; + $rowData = []; + foreach ($columns as $column) { + array_push($rowData, $column['cell']($row, ...$rest)); + } + $table->addRow($rowData); + } + } else { + return lang('Common.no_data'); + } + + return '
' . + $table->generate() . + '
'; + } +} + +// ------------------------------------------------------------------------ diff --git a/app/Helpers/form_helper.php b/app/Helpers/form_helper.php new file mode 100644 index 00000000..5be15eec --- /dev/null +++ b/app/Helpers/form_helper.php @@ -0,0 +1,187 @@ +\n"; + + $info = + '

' . + $title . + '

' . + $subtitle . + '

'; + + return $section . $info . '
'; + } +} + +//-------------------------------------------------------------------- + +if (!function_exists('form_section_close')) { + /** + * Form Section close Tag + * + * @param string $extra + * + * @return string + */ + function form_section_close(string $extra = ''): string + { + return '
' . $extra; + } +} + +//-------------------------------------------------------------------- + +if (!function_exists('form_switch')) { + /** + * Form Checkbox Switch + * + * Abstracts form_label to stylize it as a switch toggle + * + * @param array $data + * @param string $value + * @param boolean $checked + * @param mixed $extra + * + * @return string + */ + function form_switch( + $label = '', + $data = '', + string $value = '', + bool $checked = false, + $class = '', + $extra = '' + ): string { + $data['class'] = 'form-switch'; + + return ''; + } +} + +//-------------------------------------------------------------------- + +if (!function_exists('form_label')) { + /** + * Form Label Tag + * + * @param string $label_text The text to appear onscreen + * @param string $id The id the label applies to + * @param array $attributes Additional attributes + * @param string $hintText Hint text to add next to the label + * @param boolean $isOptional adds an optional text if true + * + * @return string + */ + function form_label( + string $label_text = '', + string $id = '', + array $attributes = [], + string $hintText = '', + bool $isOptional = false + ): string { + $label = ' $val) { + $label .= ' ' . $key . '="' . $val . '"'; + } + } + + $label_content = $label_text; + if ($isOptional) { + $label_content .= + '(' . + lang('Common.optional') . + ')'; + } + + if ($hintText !== '') { + $label_content .= hint_tooltip($hintText, 'ml-1'); + } + + return $label . '>' . $label_content . ''; + } +} + +//-------------------------------------------------------------------- + +if (!function_exists('form_multiselect')) { + /** + * Multi-select menu + * + * @param string $name + * @param array $options + * @param array $selected + * @param mixed $extra + * + * @return string + */ + function form_multiselect( + string $name = '', + array $options = [], + array $selected = [], + $customExtra = '' + ): string { + $defaultExtra = [ + 'data-class' => $customExtra['class'], + 'data-select-text' => lang('Common.forms.multiSelect.selectText'), + 'data-loading-text' => lang('Common.forms.multiSelect.loadingText'), + 'data-no-results-text' => lang( + 'Common.forms.multiSelect.noResultsText' + ), + 'data-no-choices-text' => lang( + 'Common.forms.multiSelect.noChoicesText' + ), + 'data-max-item-text' => lang( + 'Common.forms.multiSelect.maxItemText' + ), + ]; + $extra = stringify_attributes(array_merge($defaultExtra, $customExtra)); + + if (stripos($extra, 'multiple') === false) { + $extra .= ' multiple="multiple"'; + } + + return form_dropdown($name, $options, $selected, $extra); + } +} + +//-------------------------------------------------------------------- diff --git a/app/Helpers/rss_helper.php b/app/Helpers/rss_helper.php index 68da0f2a..532b9bcb 100644 --- a/app/Helpers/rss_helper.php +++ b/app/Helpers/rss_helper.php @@ -7,7 +7,6 @@ */ use App\Libraries\SimpleRSSElement; -use App\Models\CategoryModel; use CodeIgniter\I18n\Time; /** @@ -18,14 +17,8 @@ use CodeIgniter\I18n\Time; */ function get_rss_feed($podcast) { - $category_model = new CategoryModel(); - $episodes = $podcast->episodes; - $podcast_category = $category_model - ->where('id', $podcast->category_id) - ->first(); - $itunes_namespace = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; $rss = new SimpleRSSElement( @@ -60,39 +53,20 @@ function get_rss_feed($podcast) $itunes_image->addAttribute('href', $podcast->image->url); $channel->addChild('language', $podcast->language); - $itunes_category = $channel->addChild('category', null, $itunes_namespace); - $itunes_category->addAttribute( - 'text', - $podcast_category->parent - ? $podcast_category->parent->apple_category - : $podcast_category->apple_category - ); - - if ($podcast_category->parent) { - $itunes_category_child = $itunes_category->addChild( - 'category', - null, - $itunes_namespace - ); - $itunes_category_child->addAttribute( - 'text', - $podcast_category->apple_category - ); - $channel->addChild( - 'category', - $podcast_category->parent->apple_category - ); + // set main category first, then other categories as apple + add_category_tag($channel, $podcast->category); + foreach ($podcast->other_categories as $other_category) { + add_category_tag($channel, $other_category); } - $channel->addChild('category', $podcast_category->apple_category); $channel->addChild( 'explicit', - $podcast->explicit ? 'true' : 'false', + $podcast->parental_advisory === 'explicit' ? 'true' : 'false', $itunes_namespace ); - $podcast->author && - $channel->addChild('author', $podcast->author, $itunes_namespace); + $podcast->publisher && + $channel->addChild('author', $podcast->publisher, $itunes_namespace); $channel->addChild('link', $podcast->link); $owner = $channel->addChild('owner', null, $itunes_namespace); @@ -137,11 +111,13 @@ function get_rss_feed($podcast) $itunes_namespace ); $episode_itunes_image->addAttribute('href', $episode->image->feed_url); - $item->addChild( - 'explicit', - $episode->explicit ? 'true' : 'false', - $itunes_namespace - ); + + $episode->parental_advisory && + $item->addChild( + 'explicit', + $episode->parental_advisory === 'explicit' ? 'true' : 'false', + $itunes_namespace + ); $item->addChild('episode', $episode->number, $itunes_namespace); $episode->season_number && @@ -157,3 +133,35 @@ function get_rss_feed($podcast) return $rss->asXML(); } + +/** + * Adds and tags to node for a given category + * + * @param \SimpleXMLElement $node + * @param \App\Entities\Category $category + * + * @return void + */ +function add_category_tag($node, $category) +{ + $itunes_namespace = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; + + $itunes_category = $node->addChild('category', null, $itunes_namespace); + $itunes_category->addAttribute( + 'text', + $category->parent + ? $category->parent->apple_category + : $category->apple_category + ); + + if ($category->parent) { + $itunes_category_child = $itunes_category->addChild( + 'category', + null, + $itunes_namespace + ); + $itunes_category_child->addAttribute('text', $category->apple_category); + $node->addChild('category', $category->parent->apple_category); + } + $node->addChild('category', $category->apple_category); +} diff --git a/app/Helpers/svg_helper.php b/app/Helpers/svg_helper.php index a3b353d7..921284c9 100644 --- a/app/Helpers/svg_helper.php +++ b/app/Helpers/svg_helper.php @@ -13,16 +13,17 @@ * @param string $class to be added to the svg string * @return string svg contents */ -function icon($name, $class = null) +function icon(string $name, string $class = '') { $svg_contents = file_get_contents('assets/icons/' . $name . '.svg'); - if ($class) { + if ($class !== '') { $svg_contents = str_replace( ' 'Go to website', 'dashboard' => 'Dashboard', - 'podcasts' => 'Podcasts', - 'users' => 'Users', - 'pages' => 'Pages', 'admin' => 'Home', + 'podcasts' => 'Podcasts', 'podcast-list' => 'All podcasts', 'podcast-create' => 'New podcast', 'podcast-import' => 'Import a podcast', + 'users' => 'Users', 'user-list' => 'All users', 'user-create' => 'New user', + 'pages' => 'Pages', 'page-list' => 'All pages', 'page-create' => 'New Page', - 'go_to_website' => 'Go to website', ]; diff --git a/app/Language/en/Common.php b/app/Language/en/Common.php index ac242f8f..7e90eb89 100644 --- a/app/Language/en/Common.php +++ b/app/Language/en/Common.php @@ -7,12 +7,25 @@ */ return [ + 'yes' => 'Yes', + 'no' => 'No', + 'optional' => 'Optional', + 'no_data' => 'No data found!', 'home' => 'Home', 'explicit' => 'Explicit', 'mediumDate' => '{0,date,medium}', 'duration' => '{0,duration}', 'powered_by' => 'Powered by {castopod}.', + 'actions' => 'Actions', + 'pageInfo' => 'Page {currentPage} out of {pageCount}', 'forms' => [ + 'multiSelect' => [ + 'selectText' => 'Press to select', + 'loadingText' => 'Loading...', + 'noResultsText' => 'No results found', + 'noChoicesText' => 'No choices to choose from', + 'maxItemText' => 'Cannot add more items', + ], 'image_size_hint' => 'Image must be squared with at least 1400px wide and tall.', ], diff --git a/app/Language/en/Contributor.php b/app/Language/en/Contributor.php index 46b95f04..540dc571 100644 --- a/app/Language/en/Contributor.php +++ b/app/Language/en/Contributor.php @@ -14,6 +14,10 @@ return [ 'edit_role' => 'Update role for {0}', 'edit' => 'Edit', 'remove' => 'Remove', + 'list' => [ + 'username' => 'Username', + 'role' => 'Role', + ], 'form' => [ 'user' => 'User', 'role' => 'Role', diff --git a/app/Language/en/Episode.php b/app/Language/en/Episode.php index d2563a11..d6a01ac2 100644 --- a/app/Language/en/Episode.php +++ b/app/Language/en/Episode.php @@ -13,6 +13,9 @@ return [ 'next_season' => 'Next season', 'season' => 'Season {seasonNumber}', 'number' => 'Episode {episodeNumber}', + 'number_abbr' => 'Ep. {episodeNumber}', + 'season_episode' => 'Season {seasonNumber} episode {episodeNumber}', + 'season_episode_abbr' => 'S{seasonNumber}E{episodeNumber}', 'all_podcast_episodes' => 'All podcast episodes', 'back_to_podcast' => 'Go back to podcast', 'edit' => 'Edit', @@ -20,50 +23,51 @@ return [ 'go_to_page' => 'Go to page', 'create' => 'Add an episode', 'form' => [ - 'enclosure' => 'Audio file', + 'enclosure' => 'Choose an .mp3 or .m4a audio file…', + 'info_section_title' => 'Episode info', + 'info_section_subtitle' => '', + 'image' => 'Cover image', + 'image_hint' => + 'If you do not set an image, the podcast cover will be used instead.', 'title' => 'Title', - 'title_help' => - 'This episode title. It should contain a clear, concise name for your episode. Don’t specify the episode number or season number here.', + 'title_hint' => + 'Should contain a clear and concise episode name. Do not specify the episode or season numbers here.', 'slug' => 'Slug', - 'slug_help' => - 'This episode slug. It will be used for its URL address.', - 'description' => 'Description', - 'description_help' => - 'This is where you type the episode show notes. You may add rich text, links, images…', - 'image' => 'Image', - 'image_help' => - 'This episode image. If an image is already in the audio file, you don’t need to add one here. If you add no image to this episode, the podcast image will be used instead.', - 'explicit' => 'Explicit', - 'explicit_help' => - 'The episode parental advisory information for this episode.', - 'published_at' => [ - 'label' => 'Publication date', - 'date' => 'Publication date', - 'time' => 'Publication time', - ], - 'published_at_help' => - 'The date and time when this episode was released. It can be in the past or in the future.', + 'slug_hint' => 'Used for generating the episode URL.', + 'season_number' => 'Season', + 'episode_number' => 'Episode', 'type' => [ 'label' => 'Type', + 'hint' => + '- full: complete content the episode.
- trailer: short, promotional piece of content that represents a preview of the current show.
- bonus: extra content for the show (for example, behind the scenes info or interviews with the cast) or cross-promotional content for another show.', 'full' => 'Full', - 'full_help' => - 'Specify full when you are submitting the complete content of your episode.', 'trailer' => 'Trailer', - 'trailer_help' => - 'Specify trailer when you are submitting a short, promotional piece of content that represents a preview of your current show.', 'bonus' => 'Bonus', - 'bonus_help' => - 'Specify bonus when you are submitting extra content for your show (for example, behind the scenes information or interviews with the cast) or cross-promotional content for another show.', ], - 'episode_number' => 'Episode number', - 'episode_number_help' => - 'The episode number is mandatory for serial podcasts but optional for episodic podcasts.', - 'season_number' => 'Season number', - 'season_number_help' => - 'Season number is a non-zero integer (1, 2, 3, etc.) representing this episode season number.', - 'block' => 'Block', - 'block_help' => - 'This episode show or hide status. If you want this episode removed from the Apple directory, use this tag.', + 'show_notes_section_title' => 'Show notes', + 'show_notes_section_subtitle' => + 'Up to 4000 characters, be clear and concise. Show notes help potential listeners in finding the episode.', + 'description' => 'Description', + 'description_footer' => 'Description footer', + 'description_footer_hint' => + 'This text is added at the end of each episode description, it is a good place to input your social links for example.', + 'publication_section_title' => 'Publication info', + 'publication_section_subtitle' => '', + 'published_at' => [ + 'label' => 'Publication date', + 'date' => 'Date', + 'time' => 'Time', + ], + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does the episode contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'block' => 'Episode should be hidden from all platforms', + 'block_hint' => + 'The episode show or hide status. If you want this episode removed from the Apple directory, toggle this on.', 'submit_create' => 'Create episode', 'submit_edit' => 'Save episode', ], diff --git a/app/Language/en/Page.php b/app/Language/en/Page.php index e0f5f032..c15145b1 100644 --- a/app/Language/en/Page.php +++ b/app/Language/en/Page.php @@ -7,6 +7,7 @@ */ return [ + 'page' => 'Page', 'all_pages' => 'All pages', 'create' => 'New page', 'go_to_page' => 'Go to page', diff --git a/app/Language/en/Pager.php b/app/Language/en/Pager.php new file mode 100644 index 00000000..d18f15ed --- /dev/null +++ b/app/Language/en/Pager.php @@ -0,0 +1,19 @@ + 'Page navigation', + 'first' => 'First', + 'previous' => 'Previous', + 'next' => 'Next', + 'last' => 'Last', + 'older' => 'Older', + 'newer' => 'Newer', + 'invalidTemplate' => '{0} is not a valid Pager template.', + 'invalidPaginationGroup' => '{0} is not a valid Pagination group.', +]; diff --git a/app/Language/en/Podcast.php b/app/Language/en/Podcast.php index 2c573d72..8a86df06 100644 --- a/app/Language/en/Podcast.php +++ b/app/Language/en/Podcast.php @@ -9,8 +9,8 @@ return [ 'all_podcasts' => 'All podcasts', 'no_podcast' => 'No podcast found!', - 'create' => 'Create a Podcast', - 'import' => 'Create and Import a Podcast from an existing Feed', + 'create' => 'Create a podcast', + 'import' => 'Import a podcast', 'new_episode' => 'New Episode', 'feed' => 'RSS feed', 'view' => 'View podcast', @@ -19,93 +19,55 @@ return [ 'see_episodes' => 'See episodes', 'see_contributors' => 'See contributors', 'go_to_page' => 'Go to page', + 'latest_episodes' => 'Latest episodes', + 'see_all_episodes' => 'See all episodes', 'form' => [ + 'identity_section_title' => 'Podcast identity', + 'identity_section_subtitle' => 'These fields allow you to get noticed.', + 'image' => 'Cover image', 'title' => 'Title', - 'title_help' => - 'The podcast title will be shown on all podcasts platforms (such as Apple Podcasts) and players (such as Podcast Addict).', 'name' => 'Name', - 'name_help' => - 'The podcast will be used in the URL address. It will be used as a Fediverse actor name, (for instance, it will be the podcast Mastodon’s name).', - 'description' => 'Description', - 'description_help' => - 'It will be shown on all podcasts platforms (such as Apple Podcasts) and players (such as Podcast Addict).', - 'episode_description_footer' => 'Episode description footer', - 'episode_description_footer_help' => - 'This text will be automatically added at the end of each episode description, so that you don’t have to copy/paste it a gazillion times.', - 'image' => 'Image', - 'image_help' => - 'This podcast image. It must be square, JPEG or PNG, minimum 1400 x 1400 pixels and maximum 3000 x 3000 pixels.', - 'language' => 'Language', - 'language_help' => 'The language spoken on the podcast.', - 'category' => 'Category', - 'category_help' => - 'This podcast category. Because no one uses subcategories, Castopod does not allow you te use one.', - 'explicit' => 'Explicit', - 'explicit_help' => - 'The podcast parental advisory information. Does it contain explicit content?', - 'owner_name' => 'Owner name', - 'owner_name_help' => - 'For administrative use only. It will not be shown on podcasts platforms (such as Apple Podcasts) nor players (such as Podcast Addict) but it is visible in the public RSS feed.', - 'owner_email' => 'Owner email', - 'owner_email_help' => - 'It will be used by most platforms to verify this podcast ownership. It will not be shown on podcasts platforms (such as Apple Podcasts) nor players (such as Podcast Addict) but it is visible in the public RSS feed.', - 'author' => 'Author', - 'author_help' => - 'The group responsible for creating the show. Show author most often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', + 'name_hint' => 'Used for generating the podcast URL.', 'type' => [ 'label' => 'Type', + 'hint' => + '- episodic: if episodes are intended to be consumed without any specific order. Newest episodes will be presented first.
- serial: if episodes are intended to be consumed in sequential order. The oldest episodes will be presented first.', 'episodic' => 'Episodic', - 'episodic_help' => - 'Specify episodic when episodes are intended to be consumed without any specific order. The newest episodes will be presented first.', 'serial' => 'Serial', - 'serial_help' => - 'Specify serial when episodes are intended to be consumed in sequential order. The oldest episodes will be presented first.', ], + 'description' => 'Description', + 'classification_section_title' => 'Classification', + 'classification_section_subtitle' => + 'These fields will impact your audience and competition.', + 'language' => 'Language', + 'category' => 'Category', + 'other_categories' => 'Other categories', + 'parental_advisory' => [ + 'label' => 'Parental advisory', + 'hint' => 'Does it contain explicit content?', + 'undefined' => 'undefined', + 'clean' => 'Clean', + 'explicit' => 'Explicit', + ], + 'author_section_title' => 'Author', + 'author_section_subtitle' => 'Who is managing the podcast?', + 'owner_name' => 'Owner name', + 'owner_name_hint' => + 'For administrative use only. Visible in the public RSS feed.', + 'owner_email' => 'Owner email', + 'owner_email_hint' => + 'Will be used by most platforms to verify the podcast ownership. Visible in the public RSS feed.', + 'publisher' => 'Publisher', + 'publisher_hint' => + 'The group responsible for creating the show. Often refers to the parent company or network of a podcast. This field is sometimes labeled as ’Author’.', 'copyright' => 'Copyright', - 'copyright_help' => - 'The podcast copyright details, such as "2020 (cc)(by-nc-sa)" or "©2020".', - 'block' => 'Block', - 'block_help' => - 'If you want your show removed from all platforms, use this tag.', - 'complete' => 'Complete', - 'complete_help' => - 'Check this if you will never publish another episode to your podcast.', - 'custom_html_head' => 'Custom HTML code in ', - 'custom_html_head_help' => - 'Add here any HTML code that you would like to see on all this podcast pages within the tag.', + 'status_section_title' => 'Status', + 'status_section_subtitle' => 'Dead or alive?', + 'block' => 'Podcast should be hidden from all platforms', + 'complete' => 'Podcast will not be having new episodes', 'submit_create' => 'Create podcast', 'submit_edit' => 'Save podcast', ], - 'form_import' => [ - 'name' => 'Name', - 'name_help' => - 'This podcast name. It will be used in the URL address. It will be used as a Fediverse actor name, (for instance, it will be the podcast Mastodon’s name).', - 'imported_feed_url' => 'Feed URL', - 'imported_feed_url_help' => - 'Make sure you are legally allowed to copy that podcast.', - 'force_renumber' => 'Force episodes renumbering', - 'force_renumber_help' => - 'Use this if your old podcast does not have number but you want some on your new one.', - 'season_number' => 'Season number', - 'season_number_help' => - 'Use this if your old podcast does not have season number but you want one on your new one. Leave blank otherwise.', - 'slug_field' => [ - 'label' => 'Which field should be used to calculate episode slug', - 'link' => '<link>', - 'title' => '<title>', - ], - 'description_field' => [ - 'label' => 'Source field used for episode description / show notes', - 'description' => '<description>', - 'summary' => '<itunes:summary>', - 'subtitle_summary' => - '<itunes:subtitle> <itunes:summary>', - ], - 'max_episodes' => 'Maximum number of episodes to import', - 'max_episodes_helper' => 'Leave blank to import all episodes', - 'submit_import' => 'Import podcast', - 'submit_importing' => 'Importing podcast, this could take a while…', - ], 'category_options' => [ 'uncategorized' => 'uncategorized', 'arts' => 'Arts', @@ -219,7 +181,7 @@ return [ 'film_reviews' => 'Film Reviews', 'tv_reviews' => 'TV Reviews', ], - 'by' => 'By {author}', + 'by' => 'By {publisher}', 'season' => 'Season {seasonNumber}', 'list_of_episodes_year' => '{year} episodes', 'list_of_episodes_season' => 'Season {seasonNumber} episodes', diff --git a/app/Language/en/PodcastImport.php b/app/Language/en/PodcastImport.php new file mode 100644 index 00000000..6b86eb16 --- /dev/null +++ b/app/Language/en/PodcastImport.php @@ -0,0 +1,43 @@ + 'The podcast to import', + 'old_podcast_section_subtitle' => '', + 'imported_feed_url' => 'Feed URL', + 'imported_feed_url_hint' => + 'The feed must be in `.xml` format. Make sure you are legally allowed to copy the podcast.', + 'new_podcast_section_title' => 'The new podcast', + 'new_podcast_section_subtitle' => '', + 'name' => 'Name', + 'name_hint' => 'Used for generating the podcast URL.', + 'advanced_params_section_title' => 'Advanced parameters', + 'advanced_params_section_subtitle' => + 'Keep the default values if you have no idea of what the fields are for.', + 'slug_field' => [ + 'label' => 'Which field should be used to calculate episode slug', + 'link' => '<link>', + 'title' => '<title>', + ], + 'description_field' => [ + 'label' => 'Source field used for episode description / show notes', + 'description' => '<description>', + 'summary' => '<itunes:summary>', + 'subtitle_summary' => + '<itunes:subtitle> + <itunes:summary>', + ], + 'force_renumber' => 'Force episodes renumbering', + 'force_renumber_hint' => + 'Use this if your podcast does not have episode numbers but wish to set them during import.', + 'season_number' => 'Season number', + 'season_number_hint' => + 'Use this if your podcast does not have a season number but wish to set one during import. Leave blank otherwise.', + 'max_episodes' => 'Maximum number of episodes to import', + 'max_episodes_hint' => 'Leave blank to import all episodes', + 'submit' => 'Import podcast', +]; diff --git a/app/Language/en/PodcastNavigation.php b/app/Language/en/PodcastNavigation.php new file mode 100644 index 00000000..05fe31f1 --- /dev/null +++ b/app/Language/en/PodcastNavigation.php @@ -0,0 +1,23 @@ + 'Go to podcast page', + 'dashboard' => 'Podcast dashboard', + 'podcast-view' => 'Home', + 'podcast-edit' => 'Edit podcast', + 'episodes' => 'Episodes', + 'episode-list' => 'All episodes', + 'episode-create' => 'New episode', + 'analytics' => 'Analytics', + 'contributors' => 'Contributors', + 'contributor-list' => 'All contributors', + 'contributor-add' => 'Add contributor', + 'settings' => 'Settings', + 'platforms' => 'Podcast platforms', +]; diff --git a/app/Language/en/User.php b/app/Language/en/User.php index 2e221aaf..3c84d274 100644 --- a/app/Language/en/User.php +++ b/app/Language/en/User.php @@ -12,15 +12,21 @@ return [ 'ban' => 'Ban', 'unban' => 'Unban', 'delete' => 'Delete', - 'create' => 'Create a user', + 'create' => 'New user', 'view' => '{username}\'s info', 'all_users' => 'All users', + 'list' => [ + 'user' => 'User', + 'roles' => 'Roles', + 'banned' => 'Banned?', + ], 'form' => [ 'email' => 'Email', 'username' => 'Username', 'password' => 'Password', 'new_password' => 'New Password', 'roles' => 'Roles', + 'permissions' => 'Permissions', 'submit_create' => 'Create user', 'submit_edit' => 'Save', 'submit_password_change' => 'Change!', diff --git a/app/Libraries/Breadcrumb.php b/app/Libraries/Breadcrumb.php index 43cb2f95..816f61eb 100644 --- a/app/Libraries/Breadcrumb.php +++ b/app/Libraries/Breadcrumb.php @@ -75,7 +75,7 @@ class Breadcrumb * * @return string */ - public function render() + public function render($class = null) { $listItems = ''; $keys = array_keys($this->links); @@ -97,7 +97,9 @@ class Breadcrumb return ''; } diff --git a/app/Models/CategoryModel.php b/app/Models/CategoryModel.php index af52ff04..6764f6ed 100644 --- a/app/Models/CategoryModel.php +++ b/app/Models/CategoryModel.php @@ -53,4 +53,72 @@ class CategoryModel extends Model return $options; } + + /** + * Sets categories for a given podcast + * + * @param int $podcastId + * @param array $categories + * + * @return integer|false Number of rows inserted or FALSE on failure + */ + public function setPodcastCategories($podcastId, $categories) + { + cache()->delete("podcasts{$podcastId}_categories"); + + // Remove already previously set categories to overwrite them + $this->db + ->table('podcasts_categories') + ->delete(['podcast_id' => $podcastId]); + + if (!empty($categories)) { + // prepare data for `podcasts_categories` table + $data = array_reduce( + $categories, + function ($result, $categoryId) use ($podcastId) { + $result[] = [ + 'podcast_id' => $podcastId, + 'category_id' => $categoryId, + ]; + + return $result; + }, + [] + ); + + // Set podcast categories + return $this->db->table('podcasts_categories')->insertBatch($data); + } + + // no row has been inserted after deletion + return 0; + } + + /** + * Gets all the podcast categories + * + * @param int $podcastId + * + * @return \App\Entities\Category[] + */ + public function getPodcastCategories($podcastId) + { + if (!($categories = cache("podcasts{$podcastId}_categories"))) { + $categories = $this->select('categories.*') + ->join( + 'podcasts_categories', + 'podcasts_categories.category_id = categories.id' + ) + ->where('podcasts_categories.podcast_id', $podcastId) + ->findAll(); + + cache()->save( + "podcasts{$podcastId}_categories", + $categories, + DECADE + ); + } + + return $categories; + } } diff --git a/app/Models/EpisodeModel.php b/app/Models/EpisodeModel.php index 9eb734d8..d72f3f08 100644 --- a/app/Models/EpisodeModel.php +++ b/app/Models/EpisodeModel.php @@ -26,7 +26,7 @@ class EpisodeModel extends Model 'enclosure_filesize', 'description', 'image_uri', - 'explicit', + 'parental_advisory', 'number', 'season_number', 'type', @@ -47,7 +47,6 @@ class EpisodeModel extends Model 'slug' => 'required|regex_match[/^[a-zA-Z0-9\-]{1,191}$/]', 'enclosure_uri' => 'required', 'description' => 'required', - 'image_uri' => 'required', 'number' => 'is_natural_no_zero|permit_empty', 'season_number' => 'is_natural_no_zero|permit_empty', 'type' => 'required', diff --git a/app/Models/PodcastModel.php b/app/Models/PodcastModel.php index 16f50a26..2df72349 100644 --- a/app/Models/PodcastModel.php +++ b/app/Models/PodcastModel.php @@ -24,15 +24,14 @@ class PodcastModel extends Model 'image_uri', 'language', 'category_id', - 'explicit', + 'parental_advisory', 'owner_name', 'owner_email', - 'author', + 'publisher', 'type', 'copyright', 'block', 'complete', - 'custom_html_head', 'created_by', 'updated_by', 'imported_feed_url', diff --git a/app/Views/_assets/admin.ts b/app/Views/_assets/admin.ts index 2f390556..7967215c 100644 --- a/app/Views/_assets/admin.ts +++ b/app/Views/_assets/admin.ts @@ -1,11 +1,15 @@ import Dropdown from "./modules/Dropdown"; -import HTMLEditor from "./modules/HTMLEditor"; +import EnclosureInput from "./modules/EnclosureInput"; import MarkdownEditor from "./modules/MarkdownEditor"; +import MultiSelect from "./modules/MultiSelect"; +import SidebarToggler from "./modules/SidebarToggler"; import Slugify from "./modules/Slugify"; import Tooltip from "./modules/Tooltip"; Dropdown(); Tooltip(); MarkdownEditor(); -HTMLEditor(); +MultiSelect(); Slugify(); +SidebarToggler(); +EnclosureInput(); diff --git a/app/Views/_assets/icons/arrow-left.svg b/app/Views/_assets/icons/arrow-left.svg index 6d82f7ba..d10d02b5 100644 --- a/app/Views/_assets/icons/arrow-left.svg +++ b/app/Views/_assets/icons/arrow-left.svg @@ -1,6 +1,6 @@ - + diff --git a/app/Views/_assets/icons/caret-right.svg b/app/Views/_assets/icons/caret-right.svg new file mode 100644 index 00000000..346cb156 --- /dev/null +++ b/app/Views/_assets/icons/caret-right.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/chevron-left.svg b/app/Views/_assets/icons/chevron-left.svg new file mode 100644 index 00000000..6d82f7ba --- /dev/null +++ b/app/Views/_assets/icons/chevron-left.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/arrow-right.svg b/app/Views/_assets/icons/chevron-right.svg similarity index 100% rename from app/Views/_assets/icons/arrow-right.svg rename to app/Views/_assets/icons/chevron-right.svg diff --git a/app/Views/_assets/icons/download.svg b/app/Views/_assets/icons/download.svg new file mode 100644 index 00000000..42702f57 --- /dev/null +++ b/app/Views/_assets/icons/download.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/line-chart.svg b/app/Views/_assets/icons/line-chart.svg new file mode 100644 index 00000000..c3080e57 --- /dev/null +++ b/app/Views/_assets/icons/line-chart.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/menu.svg b/app/Views/_assets/icons/menu.svg new file mode 100644 index 00000000..666764dc --- /dev/null +++ b/app/Views/_assets/icons/menu.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/question.svg b/app/Views/_assets/icons/question.svg new file mode 100644 index 00000000..984376ae --- /dev/null +++ b/app/Views/_assets/icons/question.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/settings.svg b/app/Views/_assets/icons/settings.svg new file mode 100644 index 00000000..8ab66f65 --- /dev/null +++ b/app/Views/_assets/icons/settings.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/user-add.svg b/app/Views/_assets/icons/user-add.svg new file mode 100644 index 00000000..ab808608 --- /dev/null +++ b/app/Views/_assets/icons/user-add.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/icons/user.svg b/app/Views/_assets/icons/user.svg new file mode 100644 index 00000000..9e64bb56 --- /dev/null +++ b/app/Views/_assets/icons/user.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/Views/_assets/modules/EnclosureInput.ts b/app/Views/_assets/modules/EnclosureInput.ts new file mode 100644 index 00000000..ef6b95e1 --- /dev/null +++ b/app/Views/_assets/modules/EnclosureInput.ts @@ -0,0 +1,24 @@ +const EnclosureInput = (): void => { + const enclosureInput = document.querySelector( + ".form-enclosure-input" + ) as HTMLInputElement; + + if (enclosureInput) { + const label = enclosureInput?.nextElementSibling?.querySelector( + "span" + ) as HTMLSpanElement; + const labelVal = label.innerHTML; + + enclosureInput.addEventListener("change", (e: Event) => { + const fileName = (e.target as HTMLInputElement).value.split("\\").pop(); + + if (fileName) { + label.innerHTML = fileName; + } else { + label.innerHTML = labelVal; + } + }); + } +}; + +export default EnclosureInput; diff --git a/app/Views/_assets/modules/HTMLEditor.ts b/app/Views/_assets/modules/HTMLEditor.ts deleted file mode 100644 index 7e67b65f..00000000 --- a/app/Views/_assets/modules/HTMLEditor.ts +++ /dev/null @@ -1,19 +0,0 @@ -import CodeMirror from "codemirror"; -import "codemirror/lib/codemirror.css"; - -const HTMLEditor = (): void => { - const allHTMLEditors: NodeListOf = document.querySelectorAll( - "textarea[data-editor='html']" - ); - - for (let j = 0; j < allHTMLEditors.length; j++) { - const textarea = allHTMLEditors[j]; - - CodeMirror.fromTextArea(textarea, { - lineNumbers: true, - mode: { name: "xml", htmlMode: true }, - }); - } -}; - -export default HTMLEditor; diff --git a/app/Views/_assets/modules/MarkdownEditor.ts b/app/Views/_assets/modules/MarkdownEditor.ts index cb38bca9..604e948e 100644 --- a/app/Views/_assets/modules/MarkdownEditor.ts +++ b/app/Views/_assets/modules/MarkdownEditor.ts @@ -59,7 +59,7 @@ class ProseMirrorView { } }, attributes: { - class: "prose-sm px-3 py-2 overflow-y-auto", + class: "prose-sm px-3 py-2 overflow-y-auto focus:shadow-outline", style: "min-height: 200px; max-height: 500px", }, }); @@ -95,12 +95,22 @@ const MarkdownEditor = (): void => { "px-2", "bg-white", "border", - "text-xs" + "text-xs", + "outline-none", + "focus:shadow-outline" ); wysiwygBtn.setAttribute("type", "button"); wysiwygBtn.innerHTML = "Wysiwyg"; const markdownBtn = document.createElement("button"); - markdownBtn.classList.add("py-1", "px-2", "bg-white", "border", "text-xs"); + markdownBtn.classList.add( + "py-1", + "px-2", + "bg-white", + "border", + "text-xs", + "outline-none", + "focus:shadow-outline" + ); markdownBtn.setAttribute("type", "button"); markdownBtn.innerHTML = "Markdown"; diff --git a/app/Views/_assets/modules/MultiSelect.ts b/app/Views/_assets/modules/MultiSelect.ts new file mode 100644 index 00000000..87ef62be --- /dev/null +++ b/app/Views/_assets/modules/MultiSelect.ts @@ -0,0 +1,40 @@ +import Choices from "choices.js"; + +const MultiSelect = (): void => { + // Pass single element + const multiSelects: NodeListOf = document.querySelectorAll( + "select[multiple]" + ); + + for (let i = 0; i < multiSelects.length; i++) { + const multiSelect = multiSelects[i]; + + new Choices(multiSelect, { + maxItemCount: parseInt(multiSelect.dataset.maxItemCount || "-1"), + itemSelectText: multiSelect.dataset.selectText, + maxItemText: multiSelect.dataset.maxItemText, + removeItemButton: true, + classNames: { + containerOuter: + "multiselect" + + (multiSelect.dataset.class ? ` ${multiSelect.dataset.class}` : ""), + containerInner: "multiselect__inner", + input: "multiselect__input", + inputCloned: "multiselect__input--cloned", + list: "multiselect__list", + listItems: "multiselect__list--multiple", + listDropdown: "multiselect__list--dropdown", + item: "multiselect__item", + itemSelectable: "multiselect__item--selectable", + itemDisabled: "multiselect__item--disabled", + itemChoice: "multiselect__item--choice", + placeholder: "multiselect__placeholder", + group: "multiselect__group", + groupHeading: "multiselect__heading", + button: "multiselect__button", + }, + }); + } +}; + +export default MultiSelect; diff --git a/app/Views/_assets/modules/SidebarToggler.ts b/app/Views/_assets/modules/SidebarToggler.ts new file mode 100644 index 00000000..f9176f4f --- /dev/null +++ b/app/Views/_assets/modules/SidebarToggler.ts @@ -0,0 +1,62 @@ +const SidebarToggler = (): void => { + const sidebar = document.querySelector( + "aside[id='admin-sidebar']" + ) as HTMLElement; + const toggler = document.querySelector( + "button[id='sidebar-toggler']" + ) as HTMLButtonElement; + const sidebarBackdrop = document.querySelector( + "div[id='sidebar-backdrop']" + ) as HTMLElement; + + const setAriaExpanded = (isExpanded: "true" | "false") => { + toggler.setAttribute("aria-expanded", isExpanded); + sidebarBackdrop.setAttribute("aria-expanded", isExpanded); + }; + + const hideSidebar = () => { + setAriaExpanded("false"); + sidebar.classList.add("-translate-x-full"); + sidebarBackdrop.classList.add("hidden"); + toggler.style.transform = "translateX(0px)"; + }; + + const showSidebar = () => { + setAriaExpanded("true"); + sidebar.classList.remove("-translate-x-full"); + sidebarBackdrop.classList.remove("hidden"); + toggler.style.transform = + "translateX(" + sidebar.getBoundingClientRect().width + "px)"; + }; + + toggler.addEventListener("click", () => { + if (sidebar.classList.contains("-translate-x-full")) { + showSidebar(); + } else { + hideSidebar(); + } + }); + + sidebarBackdrop.addEventListener("click", () => { + if (!sidebar.classList.contains("-translate-x-full")) { + hideSidebar(); + } + }); + + const setAriaExpandedOnWindowEvent = () => { + const isExpanded = + !sidebar.classList.contains("-translate-x-full") || + window.innerWidth >= 768; + const ariaExpanded = toggler.getAttribute("aria-expanded"); + if (isExpanded && (!ariaExpanded || ariaExpanded === "false")) { + setAriaExpanded("true"); + } else if (!isExpanded && (!ariaExpanded || ariaExpanded === "true")) { + setAriaExpanded("false"); + } + }; + + window.addEventListener("load", setAriaExpandedOnWindowEvent); + window.addEventListener("resize", setAriaExpandedOnWindowEvent); +}; + +export default SidebarToggler; diff --git a/app/Views/_assets/modules/Tooltip.ts b/app/Views/_assets/modules/Tooltip.ts index 7f91ec0b..b8d2ab2d 100644 --- a/app/Views/_assets/modules/Tooltip.ts +++ b/app/Views/_assets/modules/Tooltip.ts @@ -10,10 +10,10 @@ const Tooltip = (): void => { const tooltipContent = tooltipReference.title; const tooltip = document.createElement("div"); - tooltip.setAttribute("id", "tooltip"); + tooltip.setAttribute("id", "tooltip" + i); tooltip.setAttribute( "class", - "px-2 py-1 text-sm bg-gray-900 text-white rounded" + "px-2 py-1 text-sm bg-gray-900 text-white rounded max-w-xs z-50" ); tooltip.innerHTML = tooltipContent; @@ -31,13 +31,13 @@ const Tooltip = (): void => { const show = () => { tooltipReference.removeAttribute("title"); - tooltipReference.setAttribute("aria-describedby", "tooltip"); + tooltipReference.setAttribute("aria-describedby", "tooltip" + i); document.body.appendChild(tooltip); popper.update(); }; const hide = () => { - const element = document.getElementById("tooltip"); + const element = document.getElementById("tooltip" + i); tooltipReference.removeAttribute("aria-describedby"); tooltipReference.setAttribute("title", tooltipContent); if (element) { diff --git a/app/Views/_assets/styles/breadcrumb.css b/app/Views/_assets/styles/breadcrumb.css index f2cb9162..0a89fe55 100644 --- a/app/Views/_assets/styles/breadcrumb.css +++ b/app/Views/_assets/styles/breadcrumb.css @@ -1,5 +1,5 @@ .breadcrumb { - @apply inline-flex flex-wrap px-1 py-2 text-sm text-gray-800; + @apply inline-flex flex-wrap px-1 py-2 text-sm; } .breadcrumb-item + .breadcrumb-item::before { diff --git a/app/Views/_assets/styles/enclosureInput.css b/app/Views/_assets/styles/enclosureInput.css new file mode 100644 index 00000000..44ea5329 --- /dev/null +++ b/app/Views/_assets/styles/enclosureInput.css @@ -0,0 +1,16 @@ +.form-enclosure-input { + @apply absolute w-0 h-0 opacity-0; +} + +.form-enclosure-input + label { + @apply inline-flex items-center justify-center w-full py-2 text-lg font-semibold text-green-600 bg-white border-2 border-green-500 rounded-lg shadow cursor-pointer; +} + +.form-enclosure-input:focus + label, +.form-enclosure-input + label:hover { + @apply text-green-700 border-green-700 shadow-md; +} + +.form-enclosure-input:focus + label { + @apply shadow-outline; +} diff --git a/app/Views/_assets/styles/index.css b/app/Views/_assets/styles/index.css index f12f46bb..d68082f6 100644 --- a/app/Views/_assets/styles/index.css +++ b/app/Views/_assets/styles/index.css @@ -1,3 +1,7 @@ @import "./tailwind.css"; @import "./layout.css"; @import "./breadcrumb.css"; +@import "./multiSelect.css"; +@import "./radioBtn.css"; +@import "./switch.css"; +@import "./enclosureInput.css"; diff --git a/app/Views/_assets/styles/layout.css b/app/Views/_assets/styles/layout.css index bed5c1eb..b613b747 100644 --- a/app/Views/_assets/styles/layout.css +++ b/app/Views/_assets/styles/layout.css @@ -1,21 +1,26 @@ .holy-grail-grid { - @apply grid; - grid-template: auto 1fr auto / auto 1fr auto; + @apply grid min-h-screen overflow-y-auto; + grid-template: 1fr auto / auto 1fr; - & .holy-grail-header { - grid-column: 1 / 4; - } - - & .holy-grail-sidenav { - grid-column: 1 / 2; - grid-row: 2 / 4; + & .holy-grail-sidebar { + @apply w-64 col-start-1 col-end-2 row-start-1 row-end-3; } & .holy-grail-main { - grid-column: 2 / 4; + @apply w-full col-start-1 col-end-3 row-start-1 row-end-2; } & .holy-grail-footer { - grid-column: 2 / 4; + @apply w-full col-start-1 col-end-3 row-start-2 row-end-3; + } + + @screen md { + & .holy-grail-main { + @apply col-start-2; + } + + & .holy-grail-footer { + @apply col-start-2; + } } } diff --git a/app/Views/_assets/styles/multiSelect.css b/app/Views/_assets/styles/multiSelect.css new file mode 100644 index 00000000..83fe9c76 --- /dev/null +++ b/app/Views/_assets/styles/multiSelect.css @@ -0,0 +1,180 @@ +/*=============================== += MultiSelect = +===============================*/ +.multiselect { + @apply relative; + + &:focus { + @apply shadow-outline outline-none; + } + &:last-child { + @apply mb-0; + } + &.is-disabled { + &.multiselect__inner, + &.multiselect__input { + @apply bg-gray-300 cursor-not-allowed select-none; + } + &.multiselect__item { + @apply cursor-not-allowed; + } + } + + & [hidden] { + @apply hidden; + } +} + +.multiselect[data-type*="select-multiple"], +.multiselect[data-type*="text"] { + & .multiselect__inner { + @apply cursor-text; + } + & .multiselect__button { + @apply relative inline-block w-2 pl-4 mt-0 mb-0 ml-1 opacity-75; + background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==); + background-size: 8px; + + &:hover, + &:focus { + @apply opacity-100; + } + } +} + +.multiselect__inner { + @apply inline-block w-full px-2 pt-2 pb-1 overflow-hidden align-top bg-white border rounded; + + &.is-focused, + &.is-open { + @apply shadow-outline; + } + &.is-open { + @apply rounded-b-none; + } + &.is-flipped.is-open { + @apply rounded-t-none; + } +} + +.multiselect__list { + @apply p-0 m-0 list-none; +} + +.multiselect__list--multiple { + @apply inline; + + & .multiselect__item { + @apply inline-flex px-2 py-1 mb-1 mr-2 text-sm text-white break-all bg-green-500 rounded; + + &[data-deletable] { + @apply pr-1; + } + & [dir="rtl"] { + @apply ml-2 mr-0; + } + &.is-highlighted { + @apply bg-green-700; + } + &.is-disabled { + @apply bg-gray-500; + } + } +} + +.multiselect__list--dropdown { + @apply absolute z-10 invisible w-full overflow-hidden break-all bg-white border border-t-0 rounded-b shadow-lg; + top: 100%; + will-change: visibility; + + &.is-active { + @apply visible; + } + &.is-open { + @apply shadow-outline; + } + &.is-flipped { + @apply top-auto mt-0 rounded-t; + bottom: 100%; + } + & .multiselect__list { + @apply relative overflow-auto; + max-height: 300px; + -webkit-overflow-scrolling: touch; + will-change: scroll-position; + } + & .multiselect__item { + @apply relative p-3; + + & [dir="rtl"] { + @apply text-right; + } + } + & .multiselect__item--selectable { + @screen sm { + padding-right: 100px; + &:after { + @apply absolute text-sm transform -translate-y-1/2 opacity-0; + content: attr(data-select-text); + right: 10px; + top: 50%; + } + & [dir="rtl"] { + @apply text-right; + padding-left: 100px; + padding-right: 10px; + &:after { + @apply right-auto; + left: 10px; + } + } + } + &.is-highlighted { + @apply bg-gray-100; + &:after { + @apply opacity-50; + } + } + } +} + +.multiselect__item { + @apply cursor-default; +} + +.multiselect__item--selectable { + @apply cursor-pointer; +} + +.multiselect__item--disabled { + @apply opacity-50 cursor-not-allowed select-none; +} + +.multiselect__heading { + @apply p-3 font-semibold text-gray-600 border-b; +} + +.multiselect__button { + @apply bg-transparent bg-center bg-no-repeat border-0 appearance-none cursor-pointer; + text-indent: -9999px; + + &:focus { + @apply outline-none; + } +} + +.multiselect__input { + @apply inline-block max-w-full py-1 pl-1 mb-1 align-baseline bg-transparent border-0 rounded-none; + &:focus { + @apply outline-none; + } + & [dir="rtl"] { + @apply pl-0 pr-1; + } +} + +.multiselect__placeholder { + @apply opacity-50; +} + +/*===== End of Choices ======*/ diff --git a/app/Views/_assets/styles/radioBtn.css b/app/Views/_assets/styles/radioBtn.css new file mode 100644 index 00000000..7e6045d6 --- /dev/null +++ b/app/Views/_assets/styles/radioBtn.css @@ -0,0 +1,24 @@ +.form-radio-btn { + @apply absolute opacity-0; +} + +.form-radio-btn:focus + label { + @apply shadow-outline; +} + +.form-radio-btn + label { + @apply px-2 py-1 text-sm text-black bg-white border rounded cursor-pointer; + + &:hover { + @apply bg-green-100; + } +} + +.form-radio-btn:checked + label { + @apply text-white bg-green-500; + + &::before { + @apply mr-2 text-green-200; + content: "✓"; + } +} diff --git a/app/Views/_assets/styles/switch.css b/app/Views/_assets/styles/switch.css new file mode 100644 index 00000000..be0cbe0f --- /dev/null +++ b/app/Views/_assets/styles/switch.css @@ -0,0 +1,26 @@ +.form-switch { + @apply absolute w-0 h-0 opacity-0; + + &:checked + .form-switch-slider { + @apply bg-green-500; + } + + &:focus + .form-switch-slider { + @apply shadow-outline; + } + + &:checked + .form-switch-slider::before { + @apply transform translate-x-5; + } +} + +.form-switch-slider { + @apply relative inset-0 flex-shrink-0 w-10 h-5 transition duration-200 bg-gray-400 rounded-full cursor-pointer; + + &::before { + @apply absolute w-4 h-4 transition duration-200 bg-white rounded-full shadow-xs; + content: ""; + left: 2px; + bottom: 2px; + } +} diff --git a/app/Views/_layout.php b/app/Views/_layout.php index 5bd01391..c2ce4918 100644 --- a/app/Views/_layout.php +++ b/app/Views/_layout.php @@ -1,6 +1,6 @@ - + @@ -9,9 +9,6 @@ - - custom_html_head ?> - @@ -25,6 +22,9 @@ diff --git a/app/Views/admin/_header.php b/app/Views/admin/_header.php deleted file mode 100644 index 274f52dc..00000000 --- a/app/Views/admin/_header.php +++ /dev/null @@ -1,28 +0,0 @@ -
- - -
- - -
-
\ No newline at end of file diff --git a/app/Views/admin/_layout.php b/app/Views/admin/_layout.php index f87c44f1..8cd3c3f1 100644 --- a/app/Views/admin/_layout.php +++ b/app/Views/admin/_layout.php @@ -1,31 +1,54 @@ - + - Castopod Admin + <?= $this->renderSection('title') ?> | Castopod Admin + - - 'flex items-center px-4 py-2 holy-grail-header', - ]) ?> - 'flex flex-col w-64 py-6 holy-grail-sidenav', - ]) ?> -
-

renderSection('title') ?>

- - renderSection('content') ?> + + + +
+
+
+
+ +

renderSection( + 'pageTitle' + ) ?>

+
+
renderSection( + 'headerRight' + ) ?>
+
+
+
+ + renderSection('content') ?> +
-
', + 'cell_start' => '', + 'cell_alt_start' => '', + + 'row_start' => '
- - - - - - - - - contributors as $contributor): ?> - - - - - - - -
UsernameRoleActions
username ?>podcast_role - ) ?> - - -
+ lang('Contributor.list.username'), + 'cell' => function ($contributor) { + return $contributor->username; + }, + ], + [ + 'header' => lang('Contributor.list.role'), + 'cell' => function ($contributor) { + return lang('Contributor.roles.' . $contributor->podcast_role); + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($contributor, $podcast) { + return button( + lang('Contributor.edit'), + route_to( + 'contributor-edit', + $podcast->id, + $contributor->id + ), + [ + 'variant' => 'info', + 'size' => 'small', + ], + ['class' => 'mr-2'] + ) . + button( + lang('Contributor.remove'), + route_to( + 'contributor-remove', + $podcast->id, + $contributor->id + ), + ['variant' => 'danger', 'size' => 'small'], + ['class' => 'mr-2'] + ); + }, + ], + ], + $podcast->contributors, + $podcast +) ?> endSection() ?> diff --git a/app/Views/admin/dashboard.php b/app/Views/admin/dashboard.php index 12e34057..214ccaaf 100644 --- a/app/Views/admin/dashboard.php +++ b/app/Views/admin/dashboard.php @@ -1,6 +1,14 @@ + extend('admin/_layout') ?> section('title') ?> -Welcome to the admin dashboard! +Dashboard endSection() ?> +section('pageTitle') ?> +Admin dashboard +endSection() ?> + +section('content') ?> +Welcome to the admin area! +endsection() ?> diff --git a/app/Views/admin/episode/create.php b/app/Views/admin/episode/create.php index 54e9832a..30bf7fc1 100644 --- a/app/Views/admin/episode/create.php +++ b/app/Views/admin/episode/create.php @@ -4,26 +4,44 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> + section('content') ?> id), [ 'method' => 'post', - 'class' => 'flex flex-col max-w-md', + 'class' => 'flex flex-col', ]) ?> - - 'enclosure', - 'name' => 'enclosure', - 'class' => 'form-input mb-4', - 'required' => 'required', - 'type' => 'file', - 'accept' => '.mp3,.m4a', -]) ?> +
+ 'enclosure', + 'name' => 'enclosure', + 'class' => 'form-enclosure-input', + 'required' => 'required', + 'type' => 'file', + 'accept' => '.mp3,.m4a', + ]) ?> + +
- + + + 'image', 'name' => 'image', @@ -35,7 +53,12 @@ 'Common.forms.image_size_hint' ) ?> - + 'title', 'name' => 'title', @@ -45,7 +68,12 @@ 'data-slugify' => 'title', ]) ?> - + 'slug', 'name' => 'slug', @@ -55,6 +83,74 @@ 'data-slugify' => 'slug', ]) ?> +
+
+ + 'season_number', + 'name' => 'season_number', + 'class' => 'form-input w-full', + 'value' => old('season_number'), + 'type' => 'number', + ]) ?> +
+
+ + 'episode_number', + 'name' => 'episode_number', + 'class' => 'form-input w-full', + 'value' => old('episode_number'), + 'required' => 'required', + 'type' => 'number', + ]) ?> +
+
+ + + 'flex mb-4 gap-1']) ?> + + + + 'full', 'name' => 'type', 'class' => 'form-radio-btn'], + 'full', + old('type') ? old('type') == 'full' : true + ) ?> + + 'trailer', 'name' => 'type', 'class' => 'form-radio-btn'], + 'trailer', + old('type') ? old('type') == 'trailer' : false + ) ?> + + 'bonus', + 'name' => 'type', + 'class' => 'form-radio-btn', + ], + 'bonus', + old('type') ? old('type') == 'bonus' : false + ) ?> + + + + + + + +
+
+ + 'description_footer', + 'name' => 'description_footer', + 'class' => 'form-textarea', + ], + old( + 'description_footer', + $podcast->episode_description_footer ?? '', + false + ), + 'data-editor="markdown"' + ) ?> +
+ + + + + + 'flex mb-4']) ?>
@@ -99,76 +225,69 @@
- - 'season_number', - 'name' => 'season_number', - 'class' => 'form-input mb-4', - 'value' => old('season_number'), - 'type' => 'number', -]) ?> - - - 'episode_number', - 'name' => 'episode_number', - 'class' => 'form-input mb-4', - 'value' => old('episode_number'), - 'required' => 'required', - 'type' => 'number', -]) ?> - - - - 'flex flex-col mb-4']) ?> - - - - + + 'clean', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'clean', + old('parental_advisory') ? old('parental_advisory') === 'clean' : false + ) ?> + + 'explicit', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'explicit', + old('parental_advisory') + ? old('parental_advisory') === 'explicit' + : false + ) ?> + - + 'block', 'name' => 'block'], + 'yes', + old('block', false) +) ?> - lang('Episode.form.submit_create'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + + + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/episode/edit.php b/app/Views/admin/episode/edit.php index 9d0ad521..155013db 100644 --- a/app/Views/admin/episode/edit.php +++ b/app/Views/admin/episode/edit.php @@ -4,25 +4,43 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> + section('content') ?> -podcast->id, $episode->id), - ['method' => 'post', 'class' => 'flex flex-col max-w-md'] -) ?> +id, $episode->id), [ + 'method' => 'post', + 'class' => 'flex flex-col', +]) ?> - - 'enclosure', - 'name' => 'enclosure', - 'class' => 'form-input mb-4', - 'type' => 'file', - 'accept' => '.mp3,.m4a', -]) ?> +
+ 'enclosure', + 'name' => 'enclosure', + 'class' => 'form-enclosure-input', + 'type' => 'file', + 'accept' => '.mp3,.m4a', + ]) ?> + +
- + + + <?= $episode->title ?> - + 'title', 'name' => 'title', @@ -49,7 +72,12 @@ 'data-slugify' => 'title', ]) ?> - + 'slug', 'name' => 'slug', @@ -59,6 +87,69 @@ 'data-slugify' => 'slug', ]) ?> +
+
+ + 'season_number', + 'name' => 'season_number', + 'class' => 'form-input w-full', + 'value' => old('season_number', $episode->season_number), + 'type' => 'number', + ]) ?> +
+
+ + 'episode_number', + 'name' => 'episode_number', + 'class' => 'form-input w-full', + 'value' => old('episode_number', $episode->number), + 'required' => 'required', + 'type' => 'number', + ]) ?> +
+
+ + 'flex mb-4 gap-1']) ?> + + + + 'full', 'name' => 'type', 'class' => 'form-radio-btn'], + 'full', + old('type') ? old('type') === 'full' : $episode->type === 'full' + ) ?> + + 'trailer', 'name' => 'type', 'class' => 'form-radio-btn'], + 'trailer', + old('type') ? old('type') === 'trailer' : $episode->type === 'trailer' + ) ?> + + 'bonus', 'name' => 'type', 'class' => 'form-radio-btn'], + 'bonus', + old('type') ? old('type') === 'bonus' : $episode->type === 'bonus' + ) ?> + + + + + + + +
+
+ + 'description_footer', + 'name' => 'description_footer', + 'class' => 'form-textarea', + ], + old( + 'description_footer', + $podcast->episode_description_footer ?? '', + false + ), + 'data-editor="markdown"' + ) ?> +
+ + + + + + 'flex mb-4']) ?>
@@ -111,76 +232,76 @@
- - 'season_number', - 'name' => 'season_number', - 'class' => 'form-input mb-4', - 'value' => old('season_number', $episode->season_number), - 'type' => 'number', -]) ?> - - 'episode_number', - 'name' => 'episode_number', - 'class' => 'form-input mb-4', - 'value' => old('episode_number', $episode->number), - 'required' => 'required', - 'type' => 'number', -]) ?> - - - - 'flex flex-col mb-4']) ?> - - - - + + 'clean', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'clean', + old('parental_advisory') + ? old('parental_advisory') === 'clean' + : $episode->parental_advisory === 'clean' + ) ?> + + 'explicit', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'explicit', + old('parental_advisory') + ? old('parental_advisory') === 'explicit' + : $episode->parental_advisory === 'explicit' + ) ?> + - + 'block', 'name' => 'block'], + 'yes', + old( + 'block', - lang('Episode.form.submit_edit'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + $episode->block + ) +) ?> + + + + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/episode/list.php b/app/Views/admin/episode/list.php index c6cfe92d..5adf9c8c 100644 --- a/app/Views/admin/episode/list.php +++ b/app/Views/admin/episode/list.php @@ -1,23 +1,130 @@ extend('admin/_layout') ?> section('title') ?> + +endSection() ?> - (episodes) ?>) - - - +section('pageTitle') ?> + (getDetails()[ + 'total' + ] ?>) +endSection() ?> +section('headerRight') ?> +id), + + ['variant' => 'primary', 'iconLeft' => 'add'] +) ?> endSection() ?> section('content') ?> - $podcast->episodes, -]) ?> +

$pager->getDetails()['currentPage'], + 'pageCount' => $pager->getDetails()['pageCount'], +]) ?>

+
+ + +
+ <?= $episode->title ?> +
+ +
+ + + +
+ +
+
+ + +

+ +
+ +links() ?> endSection() ?> diff --git a/app/Views/admin/episode/view.php b/app/Views/admin/episode/view.php index d3ccaa1e..5ecb2031 100644 --- a/app/Views/admin/episode/view.php +++ b/app/Views/admin/episode/view.php @@ -4,40 +4,46 @@ title ?> endSection() ?> +section('pageTitle') ?> +title ?> +endSection() ?> + section('content') ?> -Episode cover - +
+
+ Episode cover + - - - +
+ id, $episode->id), + ['variant' => 'info', 'iconLeft' => 'edit'] + ) ?> + name, $episode->slug), + ['variant' => 'secondary', 'iconLeft' => 'external-link'] + ) ?> + id, $episode->id), + ['variant' => 'danger', 'iconLeft' => 'delete-bin'] + ) ?> +
+
-
-description_html ?> -
+
+ description_html ?> +
+
endSection() ?> diff --git a/app/Views/admin/my_account/change_password.php b/app/Views/admin/my_account/change_password.php index 285f058e..9ae867b6 100644 --- a/app/Views/admin/my_account/change_password.php +++ b/app/Views/admin/my_account/change_password.php @@ -31,11 +31,12 @@ 'autocomplete' => 'new-password', ]) ?> - lang('User.form.submit_password_change'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/page/create.php b/app/Views/admin/page/create.php index 817a6c83..1147f9d9 100644 --- a/app/Views/admin/page/create.php +++ b/app/Views/admin/page/create.php @@ -4,6 +4,10 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> + section('content') ?> @@ -46,11 +50,13 @@ ) ?> - lang('Page.form.submit_create'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/page/edit.php b/app/Views/admin/page/edit.php index 58b99b5e..9d23cddf 100644 --- a/app/Views/admin/page/edit.php +++ b/app/Views/admin/page/edit.php @@ -4,6 +4,10 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> + section('content') ?> @@ -46,11 +50,12 @@ ) ?> - lang('Page.form.submit_edit'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/page/list.php b/app/Views/admin/page/list.php index fd2a962c..1db15fd7 100644 --- a/app/Views/admin/page/list.php +++ b/app/Views/admin/page/list.php @@ -1,47 +1,62 @@ extend('admin/_layout') ?> section('title') ?> + +endSection() ?> + +section('pageTitle') ?> () - - - +endSection() ?> + +section('headerRight') ?> + 'primary', + 'iconLeft' => 'add', +]) ?> endSection() ?> section('content') ?> - - - - - - - - - - - - - - - - - -
TitleSlugActions
title ?>slug ?> - - - -
+ lang('Page.page'), + 'cell' => function ($page) { + return '
' . + $page->title . + '/' . + $page->slug . + '
'; + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($page) { + return button( + lang('Page.go_to_page'), + route_to('page', $page->slug), + [ + 'variant' => 'secondary', + 'size' => 'small', + ], + ['class' => 'mr-2'] + ) . + button( + lang('Page.edit'), + route_to('page-edit', $page->id), + ['variant' => 'info', 'size' => 'small'], + ['class' => 'mr-2'] + ) . + button( + lang('Page.delete'), + route_to('page-delete', $page->id), + ['variant' => 'danger', 'size' => 'small'] + ); + }, + ], + ], + $pages +) ?> endSection() ?> diff --git a/app/Views/admin/page/view.php b/app/Views/admin/page/view.php index 992550e4..7a64d6f1 100644 --- a/app/Views/admin/page/view.php +++ b/app/Views/admin/page/view.php @@ -2,12 +2,17 @@ section('title') ?> title ?> - - - +endSection() ?> + +section('pageTitle') ?> +title ?> +endSection() ?> + +section('headerRight') ?> +id), [ + 'variant' => 'primary', + 'iconLeft' => 'add', +]) ?> endSection() ?> section('content') ?> diff --git a/app/Views/admin/podcast/_sidebar.php b/app/Views/admin/podcast/_sidebar.php new file mode 100644 index 00000000..23bc1f3f --- /dev/null +++ b/app/Views/admin/podcast/_sidebar.php @@ -0,0 +1,94 @@ + [ + 'icon' => 'dashboard', + 'items' => ['podcast-view', 'podcast-edit'], + ], + 'episodes' => [ + 'icon' => 'mic', + 'items' => ['episode-list', 'episode-create'], + ], + 'analytics' => [ + 'icon' => 'line-chart', + 'items' => [], + ], + 'contributors' => [ + 'icon' => 'group', + 'items' => ['contributor-list', 'contributor-add'], + ], + 'settings' => [ + 'icon' => 'settings', + 'items' => ['platforms'], + ], +]; ?> + + + + + Castopod + +
+ <?= $podcast->title ?> +
+ title ?> + @name ?> + + +
+
+ +
+ + +
diff --git a/app/Views/admin/podcast/create.php b/app/Views/admin/podcast/create.php index 4832413d..138dad7d 100644 --- a/app/Views/admin/podcast/create.php +++ b/app/Views/admin/podcast/create.php @@ -4,20 +4,30 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> + section('content') ?> 'post', - 'class' => 'flex flex-col max-w-md', + 'class' => 'flex flex-col', ]) ?> + + 'image', 'name' => 'image', 'class' => 'form-input', + 'required' => 'required', 'type' => 'file', 'accept' => '.jpg,.jpeg,.png', @@ -35,7 +45,12 @@ 'required' => 'required', ]) ?> - + 'name', 'name' => 'name', @@ -44,6 +59,33 @@ 'required' => 'required', ]) ?> + 'flex mb-4 gap-1']) ?> + + + + 'episodic', + 'name' => 'type', + 'class' => 'form-radio-btn', + ], + 'episodic', + old('type') ? old('type') == 'episodic' : true + ) ?> + + 'serial', + 'name' => 'type', + 'class' => 'form-radio-btn', + ], + 'serial', + old('type') ? old('type') == 'serial' : false + ) ?> + + +
-
- - 'episode_description_footer', - 'name' => 'episode_description_footer', - 'class' => 'form-textarea', - ], - old('episode_description_footer', '', false), - 'data-editor="markdown"' - ) ?> -
+ + + + 'required', ]) ?> - + + 'other_categories', + [], + '', + true +) ?> + 'other_categories', + 'class' => 'mb-4', + 'required' => 'required', + 'data-max-item-count' => '2', + ] +) ?> + + 'flex mb-4 gap-1']) ?> + + + + 'undefined', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'undefined', + old('parental_advisory') + ? old('parental_advisory') === 'undefined' + : true + ) ?> + + 'clean', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'clean', + old('parental_advisory') ? old('parental_advisory') === 'clean' : false + ) ?> + + 'explicit', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'explicit', + old('parental_advisory') + ? old('parental_advisory') === 'explicit' + : false + ) ?> + + + + + + + + + 'owner_name', 'name' => 'owner_name', @@ -106,7 +211,12 @@ 'required' => 'required', ]) ?> - + 'owner_email', 'name' => 'owner_email', @@ -116,37 +226,21 @@ 'required' => 'required', ]) ?> - + 'author', - 'name' => 'author', + 'id' => 'publisher', + 'name' => 'publisher', 'class' => 'form-input mb-4', - 'value' => old('author'), + 'value' => old('publisher'), ]) ?> - 'flex flex-col mb-4', -]) ?> - - - - - - + 'copyright', 'name' => 'copyright', @@ -154,42 +248,39 @@ 'value' => old('copyright'), ]) ?> - + - -
- - 'custom_html_head', - 'name' => 'custom_html_head', - 'class' => 'form-textarea', - ], - old('custom_html_head', '', false), - 'data-editor="html"' - ) ?> -
+ + + 'block', 'name' => 'block'], + 'yes', + old('block', false), + 'mb-2' +) ?> + + 'complete', 'name' => 'complete'], + 'yes', + old('complete', false) +) ?> + + + + + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> - lang('Podcast.form.submit_create'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> diff --git a/app/Views/admin/podcast/edit.php b/app/Views/admin/podcast/edit.php index 73271a3f..8b6b1c6c 100644 --- a/app/Views/admin/podcast/edit.php +++ b/app/Views/admin/podcast/edit.php @@ -4,15 +4,23 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> section('content') ?> id), [ 'method' => 'post', - 'class' => 'flex flex-col max-w-md', + 'class' => 'flex flex-col', ]) ?> + + 'required', ]) ?> - + 'name', 'name' => 'name', @@ -48,6 +61,24 @@ 'required' => 'required', ]) ?> + 'flex mb-4 gap-1']) ?> + + + 'episodic', 'name' => 'type', 'class' => 'form-radio-btn'], + 'episodic', + old('type') ? old('type') == 'episodic' : $podcast->type == 'episodic' + ) ?> + + 'serial', 'name' => 'type', 'class' => 'form-radio-btn'], + 'serial', + old('type') ? old('type') == 'serial' : $podcast->type == 'serial' + ) ?> + + +
-
- - 'episode_description_footer', - 'name' => 'episode_description_footer', - 'class' => 'form-textarea', - ], - old( - 'episode_description_footer', - $podcast->episode_description_footer, - false - ), - 'data-editor="markdown"' - ) ?> -
+ + + + category_id), + old('category', (string) $podcast->category_id), [ 'id' => 'category', 'class' => 'form-select mb-4', @@ -106,16 +125,85 @@ ] ) ?> - + +other_categories_ids), + [ + 'id' => 'other_categories', + 'class' => 'mb-4', + 'data-max-item-count' => '2', + ] +) ?> - + 'flex mb-4 gap-1']) ?> + + + 'undefined', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'undefined', + old('parental_advisory') + ? old('parental_advisory') === 'undefined' + : $podcast->parental_advisory === null + ) ?> + + 'clean', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'clean', + old('parental_advisory') + ? old('parental_advisory') === 'clean' + : $podcast->parental_advisory === 'clean' + ) ?> + + 'explicit', + 'name' => 'parental_advisory', + 'class' => 'form-radio-btn', + ], + 'explicit', + old('parental_advisory') + ? old('parental_advisory') === 'explicit' + : $podcast->parental_advisory === 'explicit' + ) ?> + + + + + + + + 'owner_name', 'name' => 'owner_name', @@ -124,7 +212,12 @@ 'required' => 'required', ]) ?> - + 'owner_email', 'name' => 'owner_email', @@ -134,37 +227,21 @@ 'required' => 'required', ]) ?> - + 'author', - 'name' => 'author', + 'id' => 'publisher', + 'name' => 'publisher', 'class' => 'form-input mb-4', - 'value' => old('author', $podcast->author), + 'value' => old('publisher', $podcast->publisher), ]) ?> - 'flex flex-col mb-4']) ?> - - - - - - + 'copyright', 'name' => 'copyright', @@ -172,42 +249,37 @@ 'value' => old('copyright', $podcast->copyright), ]) ?> - + - -
- - 'custom_html_head', - 'name' => 'custom_html_head', - 'class' => 'form-textarea', - ], - old('custom_html_head', $podcast->custom_html_head, false), - 'data-editor="html"' - ) ?> -
+ - lang('Podcast.form.submit_edit'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'block', 'name' => 'block'], + 'yes', + old('block', $podcast->block), + 'mb-2' +) ?> + + 'complete', 'name' => 'complete'], + 'yes', + old('complete', $podcast->complete) +) ?> + + + + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/podcast/import.php b/app/Views/admin/podcast/import.php index 853de899..6ec7ac58 100644 --- a/app/Views/admin/podcast/import.php +++ b/app/Views/admin/podcast/import.php @@ -4,16 +4,53 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> section('content') ?> - 'post', - 'class' => 'flex flex-col max-w-md', + 'class' => 'flex flex-col items-start', ]) ?> - + + + + 'imported_feed_url', + 'name' => 'imported_feed_url', + 'class' => 'form-input', + 'value' => old('imported_feed_url'), + 'placeholder' => 'https://...', + 'type' => 'url', + 'required' => 'required', +]) ?> + + + + + + + 'name', 'name' => 'name', @@ -22,19 +59,6 @@ 'required' => 'required', ]) ?> - - 'imported_feed_url', - 'name' => 'imported_feed_url', - 'class' => 'form-input mb-4', - 'value' => old('imported_feed_url'), - 'type' => 'url', - 'required' => 'required', -]) ?> - 'language', @@ -49,38 +73,50 @@ 'required' => 'required', ]) ?> + + + + + 'flex flex-col mb-4']) ?> - + 'flex flex-col mb-4']) ?> - + @@ -131,15 +167,21 @@ [ 'id' => 'force_renumber', 'name' => 'force_renumber', - 'class' => 'form-checkbox', + 'class' => 'form-checkbox text-green-500', ], 'yes', old('force_renumber', false) ) ?> - + + - + 'season_number', 'name' => 'season_number', @@ -148,7 +190,12 @@ 'type' => 'number', ]) ?> - + 'max_episodes', 'name' => 'max_episodes', @@ -157,11 +204,14 @@ 'type' => 'number', ]) ?> - lang('Podcast.form_import.submit_import'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + + + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/podcast/latest_episodes.php b/app/Views/admin/podcast/latest_episodes.php new file mode 100644 index 00000000..840bfa55 --- /dev/null +++ b/app/Views/admin/podcast/latest_episodes.php @@ -0,0 +1,101 @@ +
+
+

+ + + + +
+ +
+ +
+ <?= $episode->title ?> +
+
+ title ?> + +
+ season_number && + $episode->number + ): ?> + $episode->season_number, + 'episodeNumber' => $episode->number, + ] +) ?> + season_number && + $episode->number + ): ?> + $episode->number, +]) ?> + + + +
+
+
+ + +
+
+
+ +
+ +

+ +
\ No newline at end of file diff --git a/app/Views/admin/podcast/list.php b/app/Views/admin/podcast/list.php index cc1097cf..a6a00c72 100644 --- a/app/Views/admin/podcast/list.php +++ b/app/Views/admin/podcast/list.php @@ -1,17 +1,24 @@ extend('admin/_layout') ?> section('title') ?> + +endSection() ?> + +section('pageTitle') ?> () - - - - - - +endSection() ?> + +section('headerRight') ?> + 'primary', 'iconLeft' => 'add'], + ['class' => 'mr-2'] +) ?> + 'primary', + 'iconLeft' => 'download', +]) ?> endSection() ?> @@ -20,9 +27,35 @@
- $podcast, - ]) ?> +
+ <?= $podcast->title ?> +
+ +

title ?>

+
+

@name ?>

+
+
+ + +
+

diff --git a/app/Views/admin/podcast/settings/dashboard.php b/app/Views/admin/podcast/settings/dashboard.php index f7a742fd..4b9bfa56 100644 --- a/app/Views/admin/podcast/settings/dashboard.php +++ b/app/Views/admin/podcast/settings/dashboard.php @@ -4,6 +4,10 @@ endSection() ?> -section('content') ?> - +section('pageTitle') ?> + +endSection() ?> + +section('content') ?> +Podcast settings... endSection() ?> diff --git a/app/Views/admin/podcast/settings/platforms.php b/app/Views/admin/podcast/settings/platforms.php index 5137eed9..4cbdc8c0 100644 --- a/app/Views/admin/podcast/settings/platforms.php +++ b/app/Views/admin/podcast/settings/platforms.php @@ -4,6 +4,10 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> + section('content') ?> id), [ @@ -88,11 +92,12 @@ - lang('Platforms.submit'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/podcast/view.php b/app/Views/admin/podcast/view.php index e1fdba10..e0bb6aef 100644 --- a/app/Views/admin/podcast/view.php +++ b/app/Views/admin/podcast/view.php @@ -2,45 +2,29 @@ section('title') ?> title ?> - - - - - - - +endSection() ?> + +section('pageTitle') ?> +title ?> +endSection() ?> + +section('headerRight') ?> +id), + ['variant' => 'secondary', 'iconLeft' => 'edit'], + ['class' => 'mr-2'] +) ?> +id), [ + 'variant' => 'primary', + 'iconLeft' => 'add', +]) ?> endSection() ?> section('content') ?> - <?= $podcast->title ?> - - - - - $podcast->episodes, - ]) ?> + 5, +]) ?> + endSection() ?> diff --git a/app/Views/admin/user/create.php b/app/Views/admin/user/create.php index 9b860c1b..b55c0d13 100644 --- a/app/Views/admin/user/create.php +++ b/app/Views/admin/user/create.php @@ -4,12 +4,14 @@ endSection() ?> +section('pageTitle') ?> + +endSection() ?> + section('content') ?> - 'flex flex-col max-w-sm', -]) ?> + 'flex flex-col max-w-sm']) ?> @@ -33,16 +35,18 @@ 'password', 'name' => 'password', + 'class' => 'form-input mb-4', 'type' => 'password', 'autocomplete' => 'new-password', ]) ?> - lang('User.form.submit_create'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/user/edit.php b/app/Views/admin/user/edit.php index ef9fc1f2..a2693143 100644 --- a/app/Views/admin/user/edit.php +++ b/app/Views/admin/user/edit.php @@ -4,6 +4,10 @@ $user->username]) ?> endSection() ?> +section('pageTitle') ?> + $user->username]) ?> +endSection() ?> + section('content') ?> @@ -15,14 +19,15 @@ roles, [ 'id' => 'roles', - 'class' => 'form-multiselect mb-4', + 'class' => 'mb-4', ]) ?> - lang('User.form.submit_edit'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/admin/user/list.php b/app/Views/admin/user/list.php index f47b3b22..1e54610c 100644 --- a/app/Views/admin/user/list.php +++ b/app/Views/admin/user/list.php @@ -1,63 +1,89 @@ extend('admin/_layout') ?> section('title') ?> + +endSection() ?> + +section('pageTitle') ?> () endSection() ?> +section('headerRight') ?> + 'primary', + 'iconLeft' => 'user-add', +]) ?> +endSection() ?> + section('content') ?> - - - - - - - - - - - - - - - - - - - - - -
UsernameEmailRolesBanned?Actions
username ?>email ?> - [roles) ?>] - - - - isBanned() - ? 'Yes' - : 'No' ?> - - - isBanned() - ? lang('User.unban') - : lang('User.ban') ?> - -
+ lang('User.list.user'), + 'cell' => function ($user) { + return '
' . + $user->username . + '' . + $user->email . + '
'; + }, + ], + [ + 'header' => lang('User.list.roles'), + 'cell' => function ($user) { + return implode(',', $user->roles) . + icon_button( + 'edit', + lang('User.edit_roles', [ + 'username' => $user->username, + ]), + route_to('user-edit', $user->id), + ['variant' => 'info'], + ['class' => 'ml-2'] + ); + }, + ], + [ + 'header' => lang('User.list.banned'), + 'cell' => function ($user) { + return $user->isBanned() + ? lang('Common.yes') + : lang('Common.no'); + }, + ], + [ + 'header' => lang('Common.actions'), + 'cell' => function ($user) { + return button( + lang('User.forcePassReset'), + route_to('user-force_pass_reset', $user->id), + [ + 'variant' => 'secondary', + 'size' => 'small', + ], + ['class' => 'mr-2'] + ) . + button( + lang('User.' . ($user->isBanned() ? 'unban' : 'ban')), + route_to( + $user->isBanned() ? 'user-unban' : 'user-ban', + $user->id + ), + ['variant' => 'warning', 'size' => 'small'], + ['class' => 'mr-2'] + ) . + button( + lang('User.delete'), + route_to('user-delete', $user->id), + ['variant' => 'danger', 'size' => 'small'] + ); + }, + ], + ], + $users +) ?> endSection() ?> diff --git a/app/Views/auth/_layout.php b/app/Views/auth/_layout.php index 6e0a94e2..04fa7088 100644 --- a/app/Views/auth/_layout.php +++ b/app/Views/auth/_layout.php @@ -24,8 +24,9 @@ diff --git a/app/Views/auth/forgot.php b/app/Views/auth/forgot.php index 7a742021..376fa93d 100644 --- a/app/Views/auth/forgot.php +++ b/app/Views/auth/forgot.php @@ -22,11 +22,12 @@ 'required' => 'required', ]) ?> - lang('Auth.sendInstructions'), - 'type' => 'submit', - 'class' => 'px-4 py-2 ml-auto border', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/auth/login.php b/app/Views/auth/login.php index c231de54..4faf1785 100644 --- a/app/Views/auth/login.php +++ b/app/Views/auth/login.php @@ -28,11 +28,13 @@ 'required' => 'required', ]) ?> - lang('Auth.loginAction'), - 'class' => 'px-4 py-2 ml-auto border', - 'type' => 'submit', -]) ?> + + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/auth/register.php b/app/Views/auth/register.php index aa2a7db6..de58efd4 100644 --- a/app/Views/auth/register.php +++ b/app/Views/auth/register.php @@ -44,11 +44,12 @@ 'autocomplete' => 'new-password', ]) ?> - lang('Auth.register'), - 'class' => 'px-4 py-2 ml-auto border', - 'type' => 'submit', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/auth/reset.php b/app/Views/auth/reset.php index 8e26e72f..a89577ae 100644 --- a/app/Views/auth/reset.php +++ b/app/Views/auth/reset.php @@ -42,11 +42,12 @@ 'autocomplete' => 'new-password', ]) ?> - lang('Auth.resetPassword'), - 'class' => 'px-4 py-2 ml-auto border', - 'type' => 'submit', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/episode.php b/app/Views/episode.php index dbdd6a2e..40076e17 100644 --- a/app/Views/episode.php +++ b/app/Views/episode.php @@ -1,6 +1,6 @@ - + @@ -16,16 +16,16 @@
<?= $episode->podcast->title ?> - podcast->title ?> + title ?> - @podcast->name ?> + @name ?>
@@ -34,7 +34,7 @@ @@ -67,7 +67,7 @@ season_number): ?> @@ -130,7 +130,7 @@
-

podcast->copyright ?>

+

copyright ?>

'Castopod', diff --git a/app/Views/install/_layout.php b/app/Views/install/_layout.php index 81f634ff..20bd2d2a 100644 --- a/app/Views/install/_layout.php +++ b/app/Views/install/_layout.php @@ -21,6 +21,9 @@ renderSection('content') ?>

diff --git a/app/Views/install/env.php b/app/Views/install/env.php index d11b2a7f..25db9b5d 100644 --- a/app/Views/install/env.php +++ b/app/Views/install/env.php @@ -86,11 +86,12 @@ ]) ?> - lang('Install.form.submit_install'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/install/superadmin.php b/app/Views/install/superadmin.php index d4ddc61f..6b32c32c 100644 --- a/app/Views/install/superadmin.php +++ b/app/Views/install/superadmin.php @@ -41,11 +41,12 @@ ]) ?> - lang('Install.form.submit_create_superadmin'), - 'type' => 'submit', - 'class' => 'self-end px-4 py-2 bg-gray-200', -]) ?> + 'primary'], + ['type' => 'submit', 'class' => 'self-end'] +) ?> diff --git a/app/Views/pager/default_full.php b/app/Views/pager/default_full.php new file mode 100644 index 00000000..e2a065d0 --- /dev/null +++ b/app/Views/pager/default_full.php @@ -0,0 +1,67 @@ +setSurroundCount(2); ?> + + diff --git a/app/Views/podcast.php b/app/Views/podcast.php index 212be0da..2c6cb9d6 100644 --- a/app/Views/podcast.php +++ b/app/Views/podcast.php @@ -1,7 +1,7 @@ - + @@ -10,7 +10,6 @@ - custom_html_head ?> @@ -24,10 +23,10 @@
$podcast->author, + 'publisher' => $podcast->publisher, ]) ?>
- explicit + parental_advisory === 'explicit' ? '' . lang('Common.explicit') . '' @@ -48,15 +47,26 @@
-
+
description_html ?>
- + category->code ) ?> + other_categories + as $other_category + ): ?> + + code + ) ?> + +
diff --git a/composer.json b/composer.json index dc3cf041..06323749 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "myth/auth": "dev-develop", "codeigniter4/codeigniter4": "dev-develop", "league/commonmark": "^1.5", - "vlucas/phpdotenv": "^5.1", + "vlucas/phpdotenv": "^5.2", "league/html-to-markdown": "^4.10" }, "require-dev": { diff --git a/composer.lock b/composer.lock index d3126548..9e637f24 100644 --- a/composer.lock +++ b/composer.lock @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/codeigniter4/CodeIgniter4.git", - "reference": "9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4" + "reference": "9204aef421921f2c07021dda418ebfc200fe4a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4", - "reference": "9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4", + "url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/9204aef421921f2c07021dda418ebfc200fe4a31", + "reference": "9204aef421921f2c07021dda418ebfc200fe4a31", "shasum": "" }, "require": { @@ -51,6 +51,9 @@ "CodeIgniter\\ComposerScripts::postUpdate", "bash admin/setup.sh" ], + "analyze": [ + "phpstan analyze" + ], "test": [ "phpunit" ] @@ -66,7 +69,7 @@ "slack": "https://codeigniterchat.slack.com", "issues": "https://github.com/codeigniter4/CodeIgniter4/issues" }, - "time": "2020-09-07T16:29:38+00:00" + "time": "2020-09-24T17:15:24+00:00" }, { "name": "composer/ca-bundle", @@ -455,16 +458,16 @@ }, { "name": "laminas/laminas-zendframework-bridge", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "4939c81f63a8a4968c108c440275c94955753b19" + "reference": "6ede70583e101030bcace4dcddd648f760ddf642" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/4939c81f63a8a4968c108c440275c94955753b19", - "reference": "4939c81f63a8a4968c108c440275c94955753b19", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642", + "reference": "6ede70583e101030bcace4dcddd648f760ddf642", "shasum": "" }, "require": { @@ -476,10 +479,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev", - "dev-develop": "1.1.x-dev" - }, "laminas": { "module": "Laminas\\ZendFrameworkBridge" } @@ -509,20 +508,20 @@ "type": "community_bridge" } ], - "time": "2020-08-18T16:34:51+00:00" + "time": "2020-09-14T14:23:00+00:00" }, { "name": "league/commonmark", - "version": "1.5.4", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "21819c989e69bab07e933866ad30c7e3f32984ba" + "reference": "45832dfed6007b984c0d40addfac48d403dc6432" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/21819c989e69bab07e933866ad30c7e3f32984ba", - "reference": "21819c989e69bab07e933866ad30c7e3f32984ba", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/45832dfed6007b984c0d40addfac48d403dc6432", + "reference": "45832dfed6007b984c0d40addfac48d403dc6432", "shasum": "" }, "require": { @@ -534,7 +533,7 @@ }, "require-dev": { "cebe/markdown": "~1.0", - "commonmark/commonmark.js": "0.29.1", + "commonmark/commonmark.js": "0.29.2", "erusev/parsedown": "~1.0", "ext-json": "*", "github/gfm": "0.29.0", @@ -604,7 +603,7 @@ "type": "tidelift" } ], - "time": "2020-08-18T01:19:12+00:00" + "time": "2020-09-13T14:44:46+00:00" }, { "name": "league/html-to-markdown", @@ -1247,16 +1246,16 @@ }, { "name": "vlucas/phpdotenv", - "version": "v5.1.0", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "448c76d7a9e30c341ff5bc367a923af74ae18467" + "reference": "fba64139db67123c7a57072e5f8d3db10d160b66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/448c76d7a9e30c341ff5bc367a923af74ae18467", - "reference": "448c76d7a9e30c341ff5bc367a923af74ae18467", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/fba64139db67123c7a57072e5f8d3db10d160b66", + "reference": "fba64139db67123c7a57072e5f8d3db10d160b66", "shasum": "" }, "require": { @@ -1279,7 +1278,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "5.2-dev" } }, "autoload": { @@ -1319,7 +1318,7 @@ "type": "tidelift" } ], - "time": "2020-07-14T19:26:25+00:00" + "time": "2020-09-14T15:57:31+00:00" }, { "name": "whichbrowser/parser", @@ -1705,16 +1704,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.1", + "version": "5.2.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44" + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d870572532cd70bc3fab58f2e23ad423c8404c44", - "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", "shasum": "" }, "require": { @@ -1753,20 +1752,20 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-08-15T11:14:08+00:00" + "time": "2020-09-03T19:13:55+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "e878a14a65245fbe78f8080eba03b47c3b705651" + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651", - "reference": "e878a14a65245fbe78f8080eba03b47c3b705651", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", "shasum": "" }, "require": { @@ -1798,7 +1797,7 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2020-06-27T10:12:23+00:00" + "time": "2020-09-17T18:55:26+00:00" }, { "name": "phpspec/prophecy", diff --git a/package-lock.json b/package-lock.json index bc926e37..ae21fc46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1386,177 +1386,73 @@ } }, "@commitlint/cli": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-9.1.2.tgz", - "integrity": "sha512-ctRrrPqjZ8r4Vc4FXpPaScEpkPwfvB0Us3NK2SD2AnLwXGMxOLFTabDmNySU1Xc40ud2CmJsaV8lpavvzs8ZZA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-11.0.0.tgz", + "integrity": "sha512-YWZWg1DuqqO5Zjh7vUOeSX76vm0FFyz4y0cpGMFhrhvUi5unc4IVfCXZ6337R9zxuBtmveiRuuhQqnRRer+13g==", "dev": true, "requires": { - "@babel/runtime": "^7.9.6", - "@commitlint/format": "^9.1.2", - "@commitlint/lint": "^9.1.2", - "@commitlint/load": "^9.1.2", - "@commitlint/read": "^9.1.2", + "@babel/runtime": "^7.11.2", + "@commitlint/format": "^11.0.0", + "@commitlint/lint": "^11.0.0", + "@commitlint/load": "^11.0.0", + "@commitlint/read": "^11.0.0", "chalk": "4.1.0", "core-js": "^3.6.1", - "get-stdin": "7.0.0", + "get-stdin": "8.0.0", "lodash": "^4.17.19", "resolve-from": "5.0.0", "resolve-global": "1.0.0", "yargs": "^15.1.0" }, "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" + "regenerator-runtime": "^0.13.4" } }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "@commitlint/execute-rule": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-11.0.0.tgz", + "integrity": "sha512-g01p1g4BmYlZ2+tdotCavrMunnPFPhTzG1ZiLKTCYrooHRbmvqo42ZZn4QMStUEIcn+jfLb6BRZX3JzIwA1ezQ==", + "dev": true + }, + "@commitlint/load": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-11.0.0.tgz", + "integrity": "sha512-t5ZBrtgvgCwPfxmG811FCp39/o3SJ7L+SNsxFL92OR4WQxPcu6c8taD0CG2lzOHGuRyuMxZ7ps3EbngT2WpiCg==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@commitlint/execute-rule": "^11.0.0", + "@commitlint/resolve-extends": "^11.0.0", + "@commitlint/types": "^11.0.0", + "chalk": "4.1.0", + "cosmiconfig": "^7.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "@commitlint/resolve-extends": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-11.0.0.tgz", + "integrity": "sha512-WinU6Uv6L7HDGLqn/To13KM1CWvZ09VHZqryqxXa1OY+EvJkfU734CwnOEeNlSCK7FVLrB4kmodLJtL1dkEpXw==", "dev": true, "requires": { - "color-name": "~1.1.4" + "import-fresh": "^3.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "@commitlint/types": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz", + "integrity": "sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@commitlint/config-conventional": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-9.1.2.tgz", - "integrity": "sha512-2zfnsrBJuCNJEKMEmltYlCUEoQNE4anvEBI/SYEuiB1JYXYaELijobDBpqhUVjh5NEpprNTY16oMZat6ewnxOg==", - "dev": true, - "requires": { - "conventional-changelog-conventionalcommits": "4.3.0" - } - }, - "@commitlint/ensure": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-9.1.2.tgz", - "integrity": "sha512-hwQICwpNSTsZgj/1/SdPvYAzhwjwgCJI4vLbT879+Jc+AJ6sj2bUDGw/F89vzgKz1VnaMm4D65bNhoWhG3pdhQ==", - "dev": true, - "requires": { - "@commitlint/types": "^9.1.2", - "lodash": "^4.17.19" - }, - "dependencies": { - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - } - } - }, - "@commitlint/execute-rule": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-9.1.2.tgz", - "integrity": "sha512-NGbeo0KCVYo1yj9vVPFHv6RGFpIF6wcQxpFYUKGIzZVV9Vz1WyiKS689JXa99Dt1aN0cZlEJJLnTNDIgYls0Vg==", - "dev": true - }, - "@commitlint/format": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-9.1.2.tgz", - "integrity": "sha512-+ZWTOSGEU6dbn3NRh1q7sY5K5QLiSs7E2uSzuYnWHXcQk8nlTvnE0ibwMCQxdKLaOTZiN57fHM/7M9Re2gsRuw==", - "dev": true, - "requires": { - "@commitlint/types": "^9.1.2", - "chalk": "^4.0.0" - } - }, - "@commitlint/is-ignored": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-9.1.2.tgz", - "integrity": "sha512-423W/+Ro+Cc8cg81+t9gds1EscMZNjnGT31nKDvxVxJxXiXQsYYoFEQbU+nfUrRGQsUikEgEJ3ppVGr1linvcQ==", - "dev": true, - "requires": { - "@commitlint/types": "^9.1.2", - "semver": "7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - } - } - }, - "@commitlint/lint": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-9.1.2.tgz", - "integrity": "sha512-XvggqHZ4XSTKOgzJhCzz52cWRRO57QQnEviwGj0qnD4jdwC+8h2u9LNZwoa2tGAuaNM3nSm//wNK7FRZhgiiFA==", - "dev": true, - "requires": { - "@commitlint/is-ignored": "^9.1.2", - "@commitlint/parse": "^9.1.2", - "@commitlint/rules": "^9.1.2", - "@commitlint/types": "^9.1.2" - } - }, - "@commitlint/load": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-9.1.2.tgz", - "integrity": "sha512-FPL82xBuF7J3EJ57kLVoligQP4BFRwrknooP+vNT787AXmQ/Fddc/iYYwHwy67pNkk5N++/51UyDl/CqiHb6nA==", - "dev": true, - "requires": { - "@commitlint/execute-rule": "^9.1.2", - "@commitlint/resolve-extends": "^9.1.2", - "@commitlint/types": "^9.1.2", - "chalk": "4.1.0", - "cosmiconfig": "^6.0.0", - "lodash": "^4.17.19", - "resolve-from": "^5.0.0" - }, - "dependencies": { "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1593,16 +1489,16 @@ "dev": true }, "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", + "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", - "yaml": "^1.7.2" + "yaml": "^1.10.0" } }, "has-flag": { @@ -1629,12 +1525,6 @@ } } }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, "parse-json": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", @@ -1654,9 +1544,9 @@ "dev": true }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -1664,16 +1554,247 @@ } } }, - "@commitlint/message": { + "@commitlint/config-conventional": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-11.0.0.tgz", + "integrity": "sha512-SNDRsb5gLuDd2PL83yCOQX6pE7gevC79UPFx+GLbLfw6jGnnbO9/tlL76MLD8MOViqGbo7ZicjChO9Gn+7tHhA==", + "dev": true, + "requires": { + "conventional-changelog-conventionalcommits": "^4.3.1" + } + }, + "@commitlint/ensure": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-11.0.0.tgz", + "integrity": "sha512-/T4tjseSwlirKZdnx4AuICMNNlFvRyPQimbZIOYujp9DSO6XRtOy9NrmvWujwHsq9F5Wb80QWi4WMW6HMaENug==", + "dev": true, + "requires": { + "@commitlint/types": "^11.0.0", + "lodash": "^4.17.19" + }, + "dependencies": { + "@commitlint/types": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz", + "integrity": "sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ==", + "dev": true + } + } + }, + "@commitlint/execute-rule": { "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-9.1.2.tgz", - "integrity": "sha512-ndlx5z7bPVLG347oYJUHuQ41eTcsw+aUYT1ZwQyci0Duy2atpuoeeSw9SuM1PjufzRCpb6ExzFEgGzcCRKAJsg==", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-9.1.2.tgz", + "integrity": "sha512-NGbeo0KCVYo1yj9vVPFHv6RGFpIF6wcQxpFYUKGIzZVV9Vz1WyiKS689JXa99Dt1aN0cZlEJJLnTNDIgYls0Vg==", + "dev": true, + "optional": true + }, + "@commitlint/format": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-11.0.0.tgz", + "integrity": "sha512-bpBLWmG0wfZH/svzqD1hsGTpm79TKJWcf6EXZllh2J/LSSYKxGlv967lpw0hNojme0sZd4a/97R3qA2QHWWSLg==", + "dev": true, + "requires": { + "@commitlint/types": "^11.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "@commitlint/types": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz", + "integrity": "sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ==", + "dev": true + } + } + }, + "@commitlint/is-ignored": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-11.0.0.tgz", + "integrity": "sha512-VLHOUBN+sOlkYC4tGuzE41yNPO2w09sQnOpfS+pSPnBFkNUUHawEuA44PLHtDvQgVuYrMAmSWFQpWabMoP5/Xg==", + "dev": true, + "requires": { + "@commitlint/types": "^11.0.0", + "semver": "7.3.2" + }, + "dependencies": { + "@commitlint/types": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz", + "integrity": "sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "@commitlint/lint": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-11.0.0.tgz", + "integrity": "sha512-Q8IIqGIHfwKr8ecVZyYh6NtXFmKw4YSEWEr2GJTB/fTZXgaOGtGFZDWOesCZllQ63f1s/oWJYtVv5RAEuwN8BQ==", + "dev": true, + "requires": { + "@commitlint/is-ignored": "^11.0.0", + "@commitlint/parse": "^11.0.0", + "@commitlint/rules": "^11.0.0", + "@commitlint/types": "^11.0.0" + }, + "dependencies": { + "@commitlint/types": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz", + "integrity": "sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ==", + "dev": true + } + } + }, + "@commitlint/load": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-9.1.2.tgz", + "integrity": "sha512-FPL82xBuF7J3EJ57kLVoligQP4BFRwrknooP+vNT787AXmQ/Fddc/iYYwHwy67pNkk5N++/51UyDl/CqiHb6nA==", + "dev": true, + "optional": true, + "requires": { + "@commitlint/execute-rule": "^9.1.2", + "@commitlint/resolve-extends": "^9.1.2", + "@commitlint/types": "^9.1.2", + "chalk": "4.1.0", + "cosmiconfig": "^6.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "optional": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "optional": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "optional": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "optional": true + } + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true, + "optional": true + }, + "parse-json": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "dev": true, + "optional": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "optional": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@commitlint/message": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-11.0.0.tgz", + "integrity": "sha512-01ObK/18JL7PEIE3dBRtoMmU6S3ecPYDTQWWhcO+ErA3Ai0KDYqV5VWWEijdcVafNpdeUNrEMigRkxXHQLbyJA==", "dev": true }, "@commitlint/parse": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-9.1.2.tgz", - "integrity": "sha512-d+/VYbkotctW+lzDpus/R6xTerOqFQkW1myH+3PwnqYSE6JU/uHT4MlZNGJBv8pX9SPlR66t6X9puFobqtezEw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-11.0.0.tgz", + "integrity": "sha512-DekKQAIYWAXIcyAZ6/PDBJylWJ1BROTfDIzr9PMVxZRxBPc1gW2TG8fLgjZfBP5mc0cuthPkVi91KQQKGri/7A==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", @@ -1681,14 +1802,44 @@ } }, "@commitlint/read": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-9.1.2.tgz", - "integrity": "sha512-C2sNBQOqeQXMxpWtRnXYKYB3D9yuybPtQNY/P67A6o8XH/UMHkFaUTyIx1KRgu0IG0yTTItRt46FGnsMWLotvA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-11.0.0.tgz", + "integrity": "sha512-37V0V91GSv0aDzMzJioKpCoZw6l0shk7+tRG8RkW1GfZzUIytdg3XqJmM+IaIYpaop0m6BbZtfq+idzUwJnw7g==", "dev": true, "requires": { - "@commitlint/top-level": "^9.1.2", - "fs-extra": "^8.1.0", + "@commitlint/top-level": "^11.0.0", + "fs-extra": "^9.0.0", "git-raw-commits": "^2.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + } } }, "@commitlint/resolve-extends": { @@ -1696,6 +1847,7 @@ "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-9.1.2.tgz", "integrity": "sha512-HcoL+qFGmWEu9VM4fY0HI+VzF4yHcg3x+9Hx6pYFZ+r2wLbnKs964y0v68oyMO/mS/46MVoLNXZGR8U3adpadg==", "dev": true, + "optional": true, "requires": { "import-fresh": "^3.0.0", "lodash": "^4.17.19", @@ -1708,6 +1860,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, + "optional": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1717,7 +1870,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "dev": true, + "optional": true } } }, @@ -1725,48 +1879,98 @@ "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true + "dev": true, + "optional": true }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true + "dev": true, + "optional": true } } }, "@commitlint/rules": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-9.1.2.tgz", - "integrity": "sha512-1vecFuzqVqjiT57ocXq1bL8V6GEF1NZs3BR0dQzObaqHftImIxBVII299gasckTkcuxNc8M+7XxZyKxUthukpQ==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-11.0.0.tgz", + "integrity": "sha512-2hD9y9Ep5ZfoNxDDPkQadd2jJeocrwC4vJ98I0g8pNYn/W8hS9+/FuNpolREHN8PhmexXbkjrwyQrWbuC0DVaA==", "dev": true, "requires": { - "@commitlint/ensure": "^9.1.2", - "@commitlint/message": "^9.1.2", - "@commitlint/to-lines": "^9.1.2", - "@commitlint/types": "^9.1.2" + "@commitlint/ensure": "^11.0.0", + "@commitlint/message": "^11.0.0", + "@commitlint/to-lines": "^11.0.0", + "@commitlint/types": "^11.0.0" + }, + "dependencies": { + "@commitlint/types": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz", + "integrity": "sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ==", + "dev": true + } } }, "@commitlint/to-lines": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-9.1.2.tgz", - "integrity": "sha512-o4zWcMf9EnzA3MOqx01780SgrKq5hqDJmUBPk30g6an0XcDuDy3OSZHHTJFdzsg4V9FjC4OY44sFeK7GN7NaxQ==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-11.0.0.tgz", + "integrity": "sha512-TIDTB0Y23jlCNubDROUVokbJk6860idYB5cZkLWcRS9tlb6YSoeLn1NLafPlrhhkkkZzTYnlKYzCVrBNVes1iw==", "dev": true }, "@commitlint/top-level": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-9.1.2.tgz", - "integrity": "sha512-KMPP5xVePcz3B1dKqcZdU4FZBVOkT+bG3ip4RQX2TeCJoomMkTjd0utALs7rpTGLID6BXbwwXepZCZJREjR/Bw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-11.0.0.tgz", + "integrity": "sha512-O0nFU8o+Ws+py5pfMQIuyxOtfR/kwtr5ybqTvR+C2lUPer2x6lnQU+OnfD7hPM+A+COIUZWx10mYQvkR3MmtAA==", "dev": true, "requires": { - "find-up": "^4.0.0" + "find-up": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + } } }, "@commitlint/types": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", - "dev": true + "dev": true, + "optional": true }, "@csstools/convert-colors": { "version": "1.4.0", @@ -1817,12 +2021,6 @@ "resolve-from": "^4.0.0" } }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1880,9 +2078,9 @@ } }, "@popperjs/core": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.4.4.tgz", - "integrity": "sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg==" + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.5.3.tgz", + "integrity": "sha512-RFwCobxsvZ6j7twS7dHIZQZituMIDJJNHS/qY6iuthVebxS3zhRY+jaC2roEKiAYaVuTcGmX6Luc6YBcf6zJVg==" }, "@prettier/plugin-php": { "version": "0.14.3", @@ -1896,9 +2094,9 @@ } }, "@rollup/plugin-babel": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.0.tgz", - "integrity": "sha512-CPABsajaKjINgBQ3it+yMnfVO3ibsrMBxRzbUOUw2cL1hsZJ7aogU8mgglQm3S2hHJgjnAmxPz0Rq7DVdmHsTw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz", + "integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.10.4", @@ -1906,9 +2104,9 @@ } }, "@rollup/plugin-commonjs": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz", - "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz", + "integrity": "sha512-xCQqz4z/o0h2syQ7d9LskIMvBSH4PX5PjYdpSSvgS+pQik3WahkQVNWg3D8XJeYjZoVWnIUQYDghuEMRGrmQYQ==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -2014,15 +2212,6 @@ "integrity": "sha512-aPgMH+CjQiScLZculoDNOQUrrK2ktkbl3D6uCLYp1jgYRlNDrMONu9nMu8LfwAeetYNpVNeIGx7WzHSu0kvECg==", "dev": true }, - "@types/codemirror": { - "version": "0.0.97", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.97.tgz", - "integrity": "sha512-n5d7o9nWhC49DjfhsxANP7naWSeTzrjXASkUDQh7626sM4zK9XP2EVcHp1IcCf/IPV6c7ORzDUDF3Bkt231VKg==", - "dev": true, - "requires": { - "@types/tern": "*" - } - }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -2158,15 +2347,6 @@ "@types/node": "*" } }, - "@types/tern": { - "version": "0.23.3", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.3.tgz", - "integrity": "sha512-imDtS4TAoTcXk0g7u4kkWqedB3E4qpjXzCpD2LU5M5NAXHzCDsypyvXSaG7mM8DKYkCRa7tFp4tS/lp/Wo7Q3w==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", @@ -2174,13 +2354,13 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", - "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.3.0.tgz", + "integrity": "sha512-RqEcaHuEKnn3oPFislZ6TNzsBLqpZjN93G69SS+laav/I8w/iGMuMq97P0D2/2/kW4SCebHggqhbcCfbDaaX+g==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.0.1", - "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/experimental-utils": "4.3.0", + "@typescript-eslint/scope-manager": "4.3.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -2197,55 +2377,55 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", - "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.3.0.tgz", + "integrity": "sha512-cmmIK8shn3mxmhpKfzMMywqiEheyfXLV/+yPDnOTvQX/ztngx7Lg/OD26J8gTZfkLKUmaEBxO2jYP3keV7h2OQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", + "@typescript-eslint/scope-manager": "4.3.0", + "@typescript-eslint/types": "4.3.0", + "@typescript-eslint/typescript-estree": "4.3.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", - "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.3.0.tgz", + "integrity": "sha512-JyfRnd72qRuUwItDZ00JNowsSlpQGeKfl9jxwO0FHK1qQ7FbYdoy5S7P+5wh1ISkT2QyAvr2pc9dAemDxzt75g==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", + "@typescript-eslint/scope-manager": "4.3.0", + "@typescript-eslint/types": "4.3.0", + "@typescript-eslint/typescript-estree": "4.3.0", "debug": "^4.1.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", - "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.3.0.tgz", + "integrity": "sha512-cTeyP5SCNE8QBRfc+Lgh4Xpzje46kNUhXYfc3pQWmJif92sjrFuHT9hH4rtOkDTo/si9Klw53yIr+djqGZS1ig==", "dev": true, "requires": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1" + "@typescript-eslint/types": "4.3.0", + "@typescript-eslint/visitor-keys": "4.3.0" } }, "@typescript-eslint/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", - "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.3.0.tgz", + "integrity": "sha512-Cx9TpRvlRjOppGsU6Y6KcJnUDOelja2NNCX6AZwtVHRzaJkdytJWMuYiqi8mS35MRNA3cJSwDzXePfmhU6TANw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", - "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.3.0.tgz", + "integrity": "sha512-ZAI7xjkl+oFdLV/COEz2tAbQbR3XfgqHEGy0rlUXzfGQic6EBCR4s2+WS3cmTPG69aaZckEucBoTxW9PhzHxxw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1", + "@typescript-eslint/types": "4.3.0", + "@typescript-eslint/visitor-keys": "4.3.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -2263,12 +2443,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", - "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.3.0.tgz", + "integrity": "sha512-xZxkuR7XLM6RhvLkgv9yYlTcBHnTULzfnw4i6+z2TGBLy9yljAypQaZl9c3zFvy7PNI7fYWyvKYtohyF8au3cw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/types": "4.3.0", "eslint-visitor-keys": "^2.0.0" } }, @@ -2289,9 +2469,9 @@ "dev": true }, "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "dev": true }, "acorn-node": { @@ -2322,9 +2502,9 @@ } }, "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -2420,6 +2600,12 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -2682,6 +2868,12 @@ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -2697,14 +2889,6 @@ "camelcase": "^5.3.1", "map-obj": "^4.0.0", "quick-lru": "^4.0.1" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } } }, "caniuse-api": { @@ -2813,6 +2997,16 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "choices.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/choices.js/-/choices.js-9.0.1.tgz", + "integrity": "sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==", + "requires": { + "deepmerge": "^4.2.0", + "fuse.js": "^3.4.5", + "redux": "^4.0.4" + } + }, "chokidar": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", @@ -3086,11 +3280,6 @@ } } }, - "codemirror": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.57.0.tgz", - "integrity": "sha512-WGc6UL7Hqt+8a6ZAsj/f1ApQl3NPvHY/UQSzG6fB6l4BjExgVdhFaxd7mRTw1UCiYe/6q86zHP+kfvBQcZGvUg==" - }, "collapse-white-space": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", @@ -3286,41 +3475,14 @@ } }, "conventional-changelog-conventionalcommits": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.3.0.tgz", - "integrity": "sha512-oYHydvZKU+bS8LnGqTMlNrrd7769EsuEHKy4fh1oMdvvDi7fem8U+nvfresJ1IDB8K00Mn4LpiA/lR+7Gs6rgg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.4.0.tgz", + "integrity": "sha512-ybvx76jTh08tpaYrYn/yd0uJNLt5yMrb1BphDe4WBredMlvPisvMghfpnJb6RmRNcqXeuhR6LfGZGewbkRm9yA==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "lodash": "^4.17.15", "q": "^1.5.1" - }, - "dependencies": { - "compare-func": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.4.tgz", - "integrity": "sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q==", - "dev": true, - "requires": { - "array-ify": "^1.0.0", - "dot-prop": "^3.0.0" - } - }, - "dot-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", - "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - } } }, "conventional-commit-types": { @@ -3852,8 +4014,7 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, "define-properties": { "version": "1.1.3", @@ -4008,9 +4169,9 @@ } }, "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", - "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, "requires": { "is-obj": "^2.0.0" @@ -4113,6 +4274,12 @@ "is-symbol": "^1.0.2" } }, + "escalade": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz", + "integrity": "sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -4120,9 +4287,9 @@ "dev": true }, "eslint": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz", - "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.10.0.tgz", + "integrity": "sha512-BDVffmqWl7JJXqCjAK6lWtcQThZB/aP1HXSH1JKwGwv0LQEdvpR7qzNrUT487RM39B5goWuboFad5ovMBmD8yA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -4133,7 +4300,7 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", + "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^1.3.0", "espree": "^7.3.0", @@ -4201,12 +4368,6 @@ "resolve-from": "^4.0.0" } }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4243,9 +4404,9 @@ } }, "eslint-config-prettier": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", - "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.12.0.tgz", + "integrity": "sha512-9jWPlFlgNwRUYVoujvWTQ1aMO8o6648r+K7qU7K5Jmkbyqav1fuEZC0COYpGBxyiAJb65Ra9hrmFx19xRGwXWw==", "dev": true, "requires": { "get-stdin": "^6.0.0" @@ -4269,12 +4430,12 @@ } }, "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, @@ -4855,6 +5016,11 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "fuse.js": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", + "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==" + }, "generic-names": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz", @@ -4883,9 +5049,9 @@ "dev": true }, "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, "get-stream": { @@ -5168,15 +5334,15 @@ "dev": true }, "husky": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.2.5.tgz", - "integrity": "sha512-SYZ95AjKcX7goYVZtVZF2i6XiZcHknw50iXvY7b0MiGoj5RwdgRQNEHdb+gPDPCXKlzwrybjFjkL6FOj8uRhZQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz", + "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==", "dev": true, "requires": { "chalk": "^4.0.0", "ci-info": "^2.0.0", "compare-versions": "^3.6.0", - "cosmiconfig": "^6.0.0", + "cosmiconfig": "^7.0.0", "find-versions": "^3.2.0", "opencollective-postinstall": "^2.0.2", "pkg-dir": "^4.2.0", @@ -5186,16 +5352,16 @@ }, "dependencies": { "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", + "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", - "yaml": "^1.7.2" + "yaml": "^1.10.0" } }, "import-fresh": { @@ -5209,14 +5375,14 @@ } }, "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", + "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, @@ -5734,8 +5900,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.0", @@ -5859,9 +6024,9 @@ } }, "lint-staged": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.3.0.tgz", - "integrity": "sha512-an3VgjHqmJk0TORB/sdQl0CTkRg4E5ybYCXTTCSJ5h9jFwZbcgKIx5oVma5e7wp/uKt17s1QYFmYqT9MGVosGw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.4.0.tgz", + "integrity": "sha512-uaiX4U5yERUSiIEQc329vhCTDDwUcSvKdRLsNomkYLRzijk3v8V9GWm2Nz0RMVB87VcuzLvtgy6OsjoH++QHIg==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -6143,6 +6308,30 @@ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", "dev": true }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "lodash.forown": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.forown/-/lodash.forown-4.4.0.tgz", + "integrity": "sha1-hRFc8E9z75ZuztUlEdOJPMRmg68=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=", + "dev": true + }, "lodash.map": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", @@ -6155,6 +6344,12 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -6322,7 +6517,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -6447,9 +6641,9 @@ } }, "meow": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.0.tgz", - "integrity": "sha512-kq5F0KVteskZ3JdfyQFivJEj2RaA8NFsS4+r9DaMKLcUHpk5OcHS3Q0XkCXONB1mZRPsu/Y/qImKri0nwSEZog==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", + "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", "dev": true, "requires": { "@types/minimist": "^1.2.0", @@ -6546,14 +6740,6 @@ "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", "kind-of": "^6.0.3" - }, - "dependencies": { - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - } } }, "mixin-deep": { @@ -6648,14 +6834,6 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "normalize-path": { @@ -7041,57 +7219,6 @@ "dev": true, "requires": { "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } } }, "pkg-up": { @@ -7241,9 +7368,9 @@ } }, "postcss-cli": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-7.1.2.tgz", - "integrity": "sha512-3mlEmN1v2NVuosMWZM2tP8bgZn7rO5PYxRRrXtdSyL5KipcgBDjJ9ct8/LKxImMCJJi3x5nYhCGFJOkGyEqXBQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-8.0.0.tgz", + "integrity": "sha512-WgQIz1tc8htjob2DULE6dTssDzItuBh3UbscdrAlvid7M6X2WBZUrHCaLMtIuFkHFijAnimIq3nkpXV6FdDTSg==", "dev": true, "requires": { "chalk": "^4.0.0", @@ -7252,14 +7379,55 @@ "fs-extra": "^9.0.0", "get-stdin": "^8.0.0", "globby": "^11.0.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "postcss-reporter": "^6.0.0", + "postcss-load-config": "^2.1.1", + "postcss-reporter": "^7.0.0", "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", - "yargs": "^15.0.2" + "yargs": "^16.0.0" }, "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz", + "integrity": "sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "fs-extra": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", @@ -7272,10 +7440,10 @@ "universalify": "^1.0.0" } }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "jsonfile": { @@ -7288,11 +7456,79 @@ "universalify": "^1.0.0" } }, + "postcss-load-config": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.1.tgz", + "integrity": "sha512-D2ENobdoZsW0+BHy4x1CAkXtbXtYWYRIxL/JbtRBqrRGOPtJ2zoga/bEZWhV/ShWB5saVxJMzbMdSyA/vv4tXw==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, "universalify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.1.tgz", + "integrity": "sha512-/jJ831jEs4vGDbYPQp4yGKDYPSCCEQ45uZWJHE1AoYBzqdZi8+LDWas0z4HrmJXmKdpFsTiowSHXdxyFhpmdMg==", + "dev": true + }, + "yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA==", + "dev": true, + "requires": { + "cliui": "^7.0.0", + "escalade": "^3.0.2", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.1", + "yargs-parser": "^20.0.0" + } + }, + "yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-2agPoRFPoIcFzOIp6656gcvsg2ohtscpw2OINr/q46+Sq41xz2OYLqx5HRHabmFU1OARIPAYH5uteICE7mn/5A==", + "dev": true } } }, @@ -8396,37 +8632,18 @@ } }, "postcss-reporter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz", - "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.0.tgz", + "integrity": "sha512-TQ7aIDKgd7FFekFMHLRoDfl0aY3XmIAAhE4Bduyh5GvFi6uYPSVORWY4jkeC7qidFw7YtXwF5ejYQfUHOC73rQ==", "dev": true, "requires": { - "chalk": "^2.4.1", - "lodash": "^4.17.11", - "log-symbols": "^2.2.0", - "postcss": "^7.0.7" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - } + "colorette": "^1.2.1", + "lodash.difference": "^4.5.0", + "lodash.forown": "^4.4.0", + "lodash.get": "^4.4.2", + "lodash.groupby": "^4.6.0", + "lodash.sortby": "^4.7.0", + "log-symbols": "^4.0.0" } }, "postcss-resolve-nested-selector": { @@ -8555,9 +8772,9 @@ "dev": true }, "prettier": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.1.tgz", - "integrity": "sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", "dev": true }, "prettier-linter-helpers": { @@ -8729,9 +8946,9 @@ } }, "prosemirror-view": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.15.6.tgz", - "integrity": "sha512-9FBFB+rK5pvvzHsHOacy0T/Jf+OxZSzY8tSlQiur3SZwAVaNVQm+fl23V/6gU2dHBnreGxjYx9jK+F3XPsPCGw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.16.0.tgz", + "integrity": "sha512-iFtStCw2byF0yLc3mm1ezGdFSd6SWM4pnJod+ZaJiU5ju36QdYM4Xwa+qNm/AaI2/MgxpJqi8jsGWOJNkeBQ/Q==", "requires": { "prosemirror-model": "^1.1.0", "prosemirror-state": "^1.0.0", @@ -8817,14 +9034,14 @@ }, "dependencies": { "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", + "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, @@ -8907,6 +9124,15 @@ } } }, + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, "regenerate": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", @@ -8922,6 +9148,12 @@ "regenerate": "^1.4.0" } }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, "regenerator-transform": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", @@ -9155,9 +9387,9 @@ } }, "rollup": { - "version": "2.26.10", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.10.tgz", - "integrity": "sha512-dUnjCWOA0h9qNX6qtcHidyatz8FAFZxVxt1dbcGtKdlJkpSxGK3G9+DLCYvtZr9v94D129ij9zUhG+xbRoqepw==", + "version": "2.28.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.28.2.tgz", + "integrity": "sha512-8txbsFBFLmm9Xdt4ByTOGa9Muonmc8MfNjnGAR8U8scJlF1ZW7AgNZa7aqBXaKtlvnYP/ab++fQIq9dB9NWUbg==", "dev": true, "requires": { "fsevents": "~2.1.2" @@ -9266,9 +9498,9 @@ } }, "rollup-plugin-terser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.1.tgz", - "integrity": "sha512-HL0dgzSxBYG/Ly9i/E5Sc+PuKKZ0zBzk11VmLCfdUtpqH4yYqkLclPkTqRy85FU9246yetImOClaQ/ufnj08vg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", @@ -9693,9 +9925,9 @@ } }, "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", "dev": true }, "specificity": { @@ -9962,9 +10194,9 @@ } }, "stylelint": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.7.0.tgz", - "integrity": "sha512-1wStd4zVetnlHO98VjcHQbjSDmvcA39smkZQMct2cf+hom40H0xlQNdzzbswoG/jGBh61/Ue9m7Lu99PY51O6A==", + "version": "13.7.2", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.7.2.tgz", + "integrity": "sha512-mmieorkfmO+ZA6CNDu1ic9qpt4tFvH2QUB7vqXgrMVHe5ENU69q7YDq0YUg/UHLuCsZOWhUAvcMcLzLDIERzSg==", "dev": true, "requires": { "@stylelint/postcss-css-in-js": "^0.37.2", @@ -10064,9 +10296,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001124", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001124.tgz", - "integrity": "sha512-zQW8V3CdND7GHRH6rxm6s59Ww4g/qGWTheoboW9nfeMg7sUoopIfKCcNZUjwYRCOrvereh3kwDpZj4VLQ7zGtA==", + "version": "1.0.30001142", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001142.tgz", + "integrity": "sha512-pDPpn9ankEpBFZXyCv2I4lh1v/ju+bqb78QfKf+w9XgDAFWBwSYPswXqprRdrgQWK0wQnpIbfwRjNHO1HWqvoQ==", "dev": true }, "chalk": { @@ -10130,12 +10362,6 @@ "to-regex-range": "^5.0.1" } }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true - }, "global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -10192,31 +10418,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "meow": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", - "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^2.5.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" - } - }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", @@ -10381,6 +10582,11 @@ } } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -10413,9 +10619,9 @@ } }, "tailwindcss": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.7.6.tgz", - "integrity": "sha512-focAhU3ciM1/UYBHQVKKzede4zC3y9+IHzU2N/ZF6mbZbhY8S96lOxrO2Y6LMU08+Dbh2xBLmO1bsioLk3Egig==", + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.8.10.tgz", + "integrity": "sha512-7QkERG/cWCzsuMqHMwjOaLMVixOGLNBiXsrkssxlE1aWfkxVbGqiuMokR2162xRyaH2mBIHKxmlf1qb3DvIPqw==", "dev": true, "requires": { "@fullhuman/postcss-purgecss": "^2.1.2", @@ -10426,6 +10632,7 @@ "color": "^3.1.2", "detective": "^5.2.0", "fs-extra": "^8.0.0", + "html-tags": "^3.1.0", "lodash": "^4.17.20", "node-emoji": "^1.8.1", "normalize.css": "^8.0.1", @@ -10439,20 +10646,12 @@ "pretty-hrtime": "^1.0.3", "reduce-css-calc": "^2.1.6", "resolve": "^1.14.2" - }, - "dependencies": { - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - } } }, "terser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.0.tgz", - "integrity": "sha512-XTT3D3AwxC54KywJijmY2mxZ8nJiEjBHVYzq8l9OaYuRFWeQNBwvipuzzYEP4e+/AVcd1hqG/CqgsdIRyT45Fg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.2.tgz", + "integrity": "sha512-H67sydwBz5jCUA32ZRL319ULu+Su1cAoZnnc+lXnenGRYWyLE3Scgkt8mNoAsMx0h5kdo758zdoS0LG9rYZXDQ==", "dev": true, "requires": { "commander": "^2.20.0", @@ -10641,9 +10840,9 @@ } }, "typescript": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", - "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz", + "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==", "dev": true }, "uc.micro": { @@ -11093,9 +11292,9 @@ "dev": true }, "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "requires": { "cliui": "^6.0.0", @@ -11108,7 +11307,7 @@ "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" + "yargs-parser": "^18.1.2" }, "dependencies": { "ansi-regex": { @@ -11153,14 +11352,6 @@ "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } } } } diff --git a/package.json b/package.json index 258cb74f..a131f985 100644 --- a/package.json +++ b/package.json @@ -24,56 +24,55 @@ "commit": "git-cz" }, "dependencies": { - "@popperjs/core": "^2.4.4", - "codemirror": "^5.57.0", + "@popperjs/core": "^2.5.3", + "choices.js": "^9.0.1", "prosemirror-example-setup": "^1.1.2", "prosemirror-markdown": "^1.5.0", "prosemirror-state": "^1.3.3", - "prosemirror-view": "^1.15.6" + "prosemirror-view": "^1.16.0" }, "devDependencies": { "@babel/core": "^7.11.6", "@babel/plugin-proposal-class-properties": "^7.10.4", "@babel/preset-env": "^7.11.5", "@babel/preset-typescript": "^7.10.4", - "@commitlint/cli": "^9.1.2", - "@commitlint/config-conventional": "^9.1.2", + "@commitlint/cli": "^11.0.0", + "@commitlint/config-conventional": "^11.0.0", "@prettier/plugin-php": "^0.14.3", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-commonjs": "^15.0.0", + "@rollup/plugin-babel": "^5.2.1", + "@rollup/plugin-commonjs": "^15.1.0", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-multi-entry": "^4.0.0", "@rollup/plugin-node-resolve": "^9.0.0", "@tailwindcss/custom-forms": "^0.2.1", "@tailwindcss/typography": "^0.2.0", - "@types/codemirror": "0.0.97", "@types/prosemirror-markdown": "^1.0.3", "@types/prosemirror-view": "^1.15.1", - "@typescript-eslint/eslint-plugin": "^4.0.1", - "@typescript-eslint/parser": "^4.0.1", + "@typescript-eslint/eslint-plugin": "^4.3.0", + "@typescript-eslint/parser": "^4.3.0", "cross-env": "^7.0.2", "cssnano": "^4.1.10", "cz-conventional-changelog": "^3.3.0", - "eslint": "^7.8.1", - "eslint-config-prettier": "^6.11.0", + "eslint": "^7.10.0", + "eslint-config-prettier": "^6.12.0", "eslint-plugin-prettier": "^3.1.4", - "husky": "^4.2.5", - "lint-staged": "^10.3.0", - "postcss-cli": "^7.1.2", + "husky": "^4.3.0", + "lint-staged": "^10.4.0", + "postcss-cli": "^8.0.0", "postcss-import": "^12.0.1", "postcss-preset-env": "^6.7.0", - "prettier": "2.1.1", + "prettier": "2.1.2", "prettier-plugin-organize-imports": "^1.1.1", - "rollup": "^2.26.10", + "rollup": "^2.28.2", "rollup-plugin-multi-input": "^1.1.1", "rollup-plugin-node-polyfills": "^0.2.1", "rollup-plugin-postcss": "^3.1.8", - "rollup-plugin-terser": "^7.0.1", - "stylelint": "^13.7.0", + "rollup-plugin-terser": "^7.0.2", + "stylelint": "^13.7.2", "stylelint-config-standard": "^20.0.0", "svgo": "^1.3.2", - "tailwindcss": "^1.7.6", - "typescript": "^4.0.2" + "tailwindcss": "^1.8.10", + "typescript": "^4.0.3" }, "husky": { "hooks": { diff --git a/tailwind.config.js b/tailwind.config.js index 12a2371c..d4f1a1cf 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,10 +1,12 @@ /* eslint-disable */ module.exports = { - purge: ["./app/Views/**/*.php", "./app/Views/**/*.ts"], - theme: { - extend: {}, - }, + purge: [ + "./app/Views/**/*.php", + "./app/Views/**/*.ts", + "/app/Helpers/**/*.php", + ], + theme: {}, variants: { textDecoration: ["responsive", "hover", "focus", "group-hover"], }, @@ -12,4 +14,8 @@ module.exports = { require("@tailwindcss/custom-forms"), require("@tailwindcss/typography"), ], + future: { + removeDeprecatedGapUtilities: true, + purgeLayersByDefault: true, + }, };