Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • adaures/castopod
  • mkljczk/castopod-host
  • spaetz/castopod-host
  • PatrykMis/castopod
  • jonas/castopod
  • ajeremias/castopod
  • misuzu/castopod
  • KrzysztofDomanczyk/castopod
  • Behel/castopod
  • nebulon/castopod
  • ewen/castopod
  • NeoluxConsulting/castopod
  • nateritter/castopod-og
  • prcutler/castopod
14 results
Select Git revision
Show changes
Showing
with 13 additions and 2181 deletions
@layer components {
.form-radio-btn {
@apply absolute opacity-0;
}
.form-radio-btn:focus + label {
@apply ring;
}
.form-radio-btn + label {
@apply inline-block px-2 py-1 text-sm text-black bg-white border rounded cursor-pointer;
&:hover {
@apply bg-pine-100;
}
}
.form-radio-btn:checked + label {
@apply text-white bg-pine-600;
&::before {
@apply mr-2 text-pine-200;
content: "✓";
}
}
}
@layer components {
.form-switch {
@apply absolute w-0 h-0 opacity-0;
&:checked + .form-switch-slider {
@apply bg-pine-600;
}
&:focus + .form-switch-slider {
@apply ring;
}
&: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 ring-1 ring-black ring-opacity-5;
content: "";
left: 2px;
bottom: 2px;
}
}
}
@layer components {
.tabset {
@apply grid grid-cols-2;
}
.tabset > input[type="radio"] {
@apply absolute -left-full;
}
.tabset .tab-panel {
@apply hidden;
}
/* Logic for 2 tabs at most */
.tabset > input:first-child:checked ~ .tab-panels > .tab-panel:first-child,
.tabset > input:nth-child(3):checked ~ .tab-panels > .tab-panel:nth-child(2) {
@apply block;
}
/* Styling */
.tabset > label {
@apply relative inline-block w-full px-4 py-3 text-center cursor-pointer opacity-70 hover:opacity-100;
}
.tabset > input:checked + label::after {
@apply absolute inset-x-0 bottom-0 w-1/2 h-1 mx-auto bg-pine-700;
content: "";
}
.tabset > input:checked + label {
@apply font-semibold opacity-100 text-pine-700;
}
.tabset .tab-panels {
@apply col-span-2 p-6;
}
}
declare module "prosemirror-markdown";
declare module "prosemirror-example-setup";
<?= helper('page') ?>
<!DOCTYPE html>
<html lang="<?= service('request')->getLocale() ?>">
<head>
<meta charset="UTF-8"/>
<title><?= $this->renderSection('title') ?></title>
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
<link rel="stylesheet" href="/assets/index.css"/>
</head>
<body class="flex flex-col min-h-screen mx-auto bg-gray-100">
<header class="bg-white border-b">
<div class="container flex items-center justify-between px-2 py-4 mx-auto">
<a href="<?= route_to('home') ?>" class="text-2xl"><?= isset($page)
? $page->title
: 'Castopod' ?></a>
</div>
</header>
<main class="container flex-1 px-4 py-10 mx-auto">
<?= $this->renderSection('content') ?>
</main>
<footer class="px-2 py-4 bg-white border-t">
<div class="container flex flex-col items-center justify-between mx-auto text-xs md:flex-row ">
<?= render_page_links('inline-flex mb-4 md:mb-0') ?>
<p class="flex flex-col items-center md:items-end">
<?= lang('Common.powered_by', [
'castopod' =>
'<a class="underline hover:no-underline" href="https://castopod.org" target="_blank" rel="noreferrer noopener">Castopod</a>',
]) ?>
</p>
</div>
</footer>
</body>
<?php if (session()->has('message')): ?>
<div class="px-4 py-2 mb-4 font-semibold text-green-900 bg-green-200 border border-green-700">
<?= session('message') ?>
</div>
<?php declare(strict_types=1);
if (session()->has('message')): ?>
<Alert variant="success" class="mb-4"><?= session('message') ?></Alert>
<?php endif; ?>
<?php if (session()->has('error')): ?>
<div class="px-4 py-2 mb-4 font-semibold text-red-900 bg-red-200 border border-red-700">
<?= session('error') ?>
</div>
<Alert variant="danger" class="mb-4"><?= session('error') ?></Alert>
<?php endif; ?>
<?php if (session()->has('errors')): ?>
<ul class="px-4 py-2 mb-4 font-semibold text-red-900 bg-red-200 border border-red-700">
<?php foreach (session('errors') as $error): ?>
<li><?= $error ?></li>
<?php endforeach; ?>
</ul>
<?php endif;
?>
<Alert variant="danger" class="mb-4">
<ul>
<?php foreach (session('errors') as $error): ?>
<li><?= $error ?></li>
<?php endforeach; ?>
</ul>
</Alert>
<?php endif; ?>
<!DOCTYPE html>
<html lang="<?= service('request')->getLocale() ?>">
<head>
<meta charset="UTF-8"/>
<title><?= $this->renderSection('title') ?> | Castopod Admin</title>
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
<link rel="stylesheet" href="/assets/admin.css"/>
<link rel="stylesheet" href="/assets/index.css"/>
<script src="/assets/admin.js" type="module"></script>
</head>
<body class="relative bg-gray-100 holy-grail-grid">
<div id="sidebar-backdrop" role="button" tabIndex="0" aria-label="Close" class="fixed z-50 hidden w-full h-full bg-gray-900 bg-opacity-50 md:hidden"></div>
<aside id="admin-sidebar" class="sticky top-0 z-50 flex flex-col max-h-screen transition duration-200 ease-in-out transform -translate-x-full bg-white border-r w-80 holy-grail-sidebar md:translate-x-0">
<?php if (isset($podcast)): ?>
<?= $this->include('admin/podcast/_sidebar') ?>
<?php else: ?>
<?= $this->include('admin/_sidebar') ?>
<?php endif; ?>
</aside>
<main class="overflow-hidden holy-grail-main">
<header class="text-white bg-pine-900">
<div class="container flex flex-wrap items-end justify-between px-2 py-10 mx-auto md:px-12 gap-y-6 gap-x-6">
<div class="flex flex-col">
<?= render_breadcrumb('text-gray-300') ?>
<div class="flex flex-wrap items-center">
<h1 class="text-3xl font-bold font-display"><?= $this->renderSection(
'pageTitle',
) ?></h1>
<?= $this->renderSection('headerLeft') ?>
</div>
</div>
<div class="flex flex-wrap"><?= $this->renderSection(
'headerRight',
) ?></div>
</div>
</header>
<div class="container px-2 py-8 mx-auto md:px-12">
<?= view('_message_block') ?>
<?= $this->renderSection('content') ?>
</div>
</main>
<footer class="px-2 py-2 mx-auto text-xs text-right holy-grail-footer">
<?= lang('Common.powered_by', [
'castopod' =>
'<a class="underline hover:no-underline" href="https://castopod.org/" target="_blank" rel="noreferrer noopener">Castopod</a> v' .
CP_VERSION,
]) ?>
</footer>
<button
type="button"
id="sidebar-toggler"
class="fixed bottom-0 left-0 z-50 p-3 mb-3 ml-3 text-xl transition duration-300 ease-in-out bg-white border-2 rounded-full shadow-lg focus:outline-none md:hidden hover:bg-gray-100 focus:ring"
style="transform: translateX(0px);"><?= icon('menu') ?></button>
</body>
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium leading-5 text-gray-500">
<?= lang('User.form.email') ?>
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<?= $user->email ?>
</dd>
</div>
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium leading-5 text-gray-500">
<?= lang('User.form.username') ?>
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<?= $user->username ?>
</dd>
</div>
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium leading-5 text-gray-500">
<?= lang('User.form.roles') ?>
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
[<?= implode(', ', $user->roles) ?>]
</dd>
</div>
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium leading-5 text-gray-500">
<?= lang('User.form.permissions') ?>
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
[<?= implode(', ', $user->permissions) ?>]
</dd>
</div>
<?php
$navigation = [
'podcasts' => [
'icon' => 'mic',
'items' => ['podcast-list', 'podcast-create', 'podcast-import'],
],
'persons' => [
'icon' => 'folder-user',
'items' => ['person-list', 'person-create'],
],
'fediverse' => [
'icon' => 'star-smile',
'items' => ['fediverse-blocked-actors', 'fediverse-blocked-domains'],
],
'users' => ['icon' => 'group', 'items' => ['user-list', 'user-create']],
'pages' => ['icon' => 'pages', 'items' => ['page-list', 'page-create']],
]; ?>
<a href="<?= route_to(
'admin',
) ?>" class="inline-flex items-baseline px-6 py-2 mb-2 text-2xl font-semibold font-display text-pine-700">
<?= 'castopod' . svg('castopod-logo', 'h-5 ml-1') ?>
</a>
<a href="<?= route_to(
'home',
) ?>" class="inline-flex items-center px-6 py-2 mb-2 text-sm underline outline-none hover:no-underline focus:ring">
<?= lang('AdminNavigation.go_to_website') ?>
<?= icon('external-link', 'ml-2 text-gray-500') ?>
</a>
<nav class="flex flex-col flex-1 overflow-y-auto">
<?php foreach ($navigation as $section => $data): ?>
<div class="mb-4">
<button class="inline-flex items-center w-full px-6 py-1 font-semibold text-gray-600 outline-none focus:ring" type="button">
<?= icon($data['icon'], 'text-gray-400 text-xl mr-3') ?>
<?= lang('AdminNavigation.' . $section) ?>
</button>
<ul class="flex flex-col">
<?php foreach ($data['items'] as $item): ?>
<?php $isActive = url_is(route_to($item)); ?>
<li class="inline-flex">
<a class="w-full py-1 pl-14 pr-2 text-sm text-gray-600 outline-none hover:text-gray-900 focus:ring <?= $isActive
? 'font-semibold text-gray-900'
: '' ?>" href="<?= route_to($item) ?>"><?= lang(
'AdminNavigation.' . $item,
) ?></a>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endforeach; ?>
</nav>
<button
type="button"
class="inline-flex items-center w-full px-6 py-2 mt-auto border-t outline-none focus:ring"
id="my-account-dropdown"
data-dropdown="button"
data-dropdown-target="my-account-dropdown-menu"
aria-haspopup="true"
aria-expanded="false">
<?= icon('user', 'text-gray-500 mr-2') ?>
<?= user()->username ?>
<?= icon('caret-right', 'ml-auto') ?>
</button>
<nav
id="my-account-dropdown-menu"
class="absolute z-50 flex flex-col py-2 text-black whitespace-no-wrap bg-white border rounded shadow"
aria-labelledby="my-accountDropdown"
data-dropdown="menu"
data-dropdown-placement="right-end">
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'my-account',
) ?>"><?= lang('AdminNavigation.account.my-account') ?></a>
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'change-password',
) ?>"><?= lang('AdminNavigation.account.change-password') ?></a>
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'logout',
) ?>"><?= lang('AdminNavigation.account.logout') ?></a>
</nav>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Contributor.add_contributor', [$podcast->title]) ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Contributor.add_contributor', [$podcast->title]) ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_open(route_to('contributor-add', $podcast->id), [
'class' => 'flex flex-col max-w-sm',
]) ?>
<?= csrf_field() ?>
<?= form_label(lang('Contributor.form.user'), 'user') ?>
<?= form_dropdown('user', $userOptions, old('user'), [
'id' => 'user',
'class' => 'form-select mb-4',
'required' => 'required',
]) ?>
<?= form_label(lang('Contributor.form.role'), 'role') ?>
<?= form_dropdown('role', $roleOptions, old('role'), [
'id' => 'role',
'class' => 'form-select mb-4',
'required' => 'required',
]) ?>
<?= button(
lang('Contributor.form.submit_add'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Contributor.edit_role', [$user->username]) ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Contributor.edit_role', [$user->username]) ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_open(route_to('contributor-edit', $podcast->id, $user->id), [
'class' => 'flex flex-col max-w-sm',
]) ?>
<?= csrf_field() ?>
<?= form_label(lang('Contributor.form.role'), 'role') ?>
<?= form_dropdown('role', $roleOptions, old('role', $contributorGroupId), [
'id' => 'role',
'class' => 'form-select mb-4',
'required' => 'required',
]) ?>
<?= button(
lang('Contributor.form.submit_edit'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Contributor.podcast_contributors') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Contributor.podcast_contributors') ?>
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(lang('Contributor.add'), route_to('contributor-add', $podcast->id), [
'variant' => 'accent',
'iconLeft' => 'add',
]) ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= data_table(
[
[
'header' => 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,
) ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Contributor.view', [
'username' => $contributor->username,
'podcastName' => $contributor->podcast->name,
]) ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium leading-5 text-gray-500">
Username
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<?= $contributor->username ?>
</dd>
</div>
<div class="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium leading-5 text-gray-500">
Role
</dt>
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
<?= $contributor->podcast_role ?>
</dd>
</div>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Episode.create') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Episode.create') ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_open_multipart(route_to('episode-create', $podcast->id), [
'method' => 'post',
'class' => 'flex flex-col',
]) ?>
<?= csrf_field() ?>
<?= form_hidden('client_timezone', 'UTC') ?>
<div class="inline-flex w-full p-2 mb-4 text-sm font-semibold text-yellow-800 bg-red-100 border border-red-300 rounded" role="alert">
<?= icon('alert', 'mr-2 text-lg flex-shrink-0') .
lang('Episode.form.warning') ?>
</div>
<?= form_section(
lang('Episode.form.info_section_title'),
lang('Episode.form.info_section_subtitle'),
) ?>
<?= form_label(
lang('Episode.form.audio_file'),
'audio_file',
[],
lang('Episode.form.audio_file_hint'),
) ?>
<?= form_input([
'id' => 'audio_file',
'name' => 'audio_file',
'class' => 'form-input mb-4',
'required' => 'required',
'type' => 'file',
'accept' => '.mp3,.m4a',
]) ?>
<?= form_label(
lang('Episode.form.image'),
'image',
[],
lang('Episode.form.image_hint'),
true,
) ?>
<?= form_input([
'id' => 'image',
'name' => 'image',
'class' => 'form-input',
'type' => 'file',
'accept' => '.jpg,.jpeg,.png',
]) ?>
<small class="mb-4 text-gray-600"><?= lang(
'Common.forms.image_size_hint',
) ?></small>
<?= form_label(
lang('Episode.form.title'),
'title',
[],
lang('Episode.form.title_hint'),
) ?>
<?= form_input([
'id' => 'title',
'name' => 'title',
'class' => 'form-input mb-4',
'value' => old('title'),
'required' => 'required',
'data-slugify' => 'title',
]) ?>
<?= form_label(
lang('Episode.form.slug'),
'slug',
[],
lang('Episode.form.slug_hint'),
) ?>
<?= form_input([
'id' => 'slug',
'name' => 'slug',
'class' => 'form-input mb-4',
'value' => old('slug'),
'required' => 'required',
'data-slugify' => 'slug',
]) ?>
<div class="flex flex-col mb-4 gap-x-2 gap-y-4 md:flex-row">
<div class="flex flex-col flex-1">
<?= form_label(lang('Episode.form.season_number'), 'season_number') ?>
<?= form_input([
'id' => 'season_number',
'name' => 'season_number',
'class' => 'form-input w-full',
'value' => old('season_number'),
'type' => 'number',
]) ?>
</div>
<div class="flex flex-col flex-1">
<?= form_label(lang('Episode.form.episode_number'), 'episode_number') ?>
<?= form_input([
'id' => 'episode_number',
'name' => 'episode_number',
'class' => 'form-input w-full',
'value' => old('episode_number'),
'type' => 'number',
]) ?>
</div>
</div>
<?= form_fieldset('', ['class' => 'mb-4']) ?>
<legend>
<?= lang('Episode.form.type.label') .
hint_tooltip(lang('Episode.form.type.hint'), 'ml-1') ?>
</legend>
<?= form_radio(
['id' => 'full', 'name' => 'type', 'class' => 'form-radio-btn'],
'full',
old('type') ? old('type') == 'full' : true,
) ?>
<label for="full" class="inline-flex items-center">
<?= lang('Episode.form.type.full') ?>
</label>
<?= form_radio(
['id' => 'trailer', 'name' => 'type', 'class' => 'form-radio-btn'],
'trailer',
old('type') && old('type') == 'trailer',
) ?>
<label for="trailer" class="inline-flex items-center">
<?= lang('Episode.form.type.trailer') ?>
</label>
<?= form_radio(
['id' => 'bonus', 'name' => 'type', 'class' => 'form-radio-btn'],
'bonus',
old('type') && old('type') == 'bonus',
) ?>
<label for="bonus" class="inline-flex items-center">
<?= lang('Episode.form.type.bonus') ?>
</label>
<?= form_fieldset_close() ?>
<?= form_fieldset('', ['class' => 'flex mb-6 gap-1']) ?>
<legend>
<?= lang('Episode.form.parental_advisory.label') .
hint_tooltip(lang('Episode.form.parental_advisory.hint'), 'ml-1') ?>
</legend>
<?= form_radio(
[
'id' => 'undefined',
'name' => 'parental_advisory',
'class' => 'form-radio-btn',
],
'undefined',
old('parental_advisory')
? old('parental_advisory') === 'undefined'
: true,
) ?>
<label for="undefined"><?= lang(
'Episode.form.parental_advisory.undefined',
) ?></label>
<?= form_radio(
[
'id' => 'clean',
'name' => 'parental_advisory',
'class' => 'form-radio-btn',
],
'clean',
old('parental_advisory') && old('parental_advisory') === 'clean',
) ?>
<label for="clean"><?= lang(
'Episode.form.parental_advisory.clean',
) ?></label>
<?= form_radio(
[
'id' => 'explicit',
'name' => 'parental_advisory',
'class' => 'form-radio-btn',
],
'explicit',
old('parental_advisory') && old('parental_advisory') === 'explicit',
) ?>
<label for="explicit"><?= lang(
'Episode.form.parental_advisory.explicit',
) ?></label>
<?= form_fieldset_close() ?>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.show_notes_section_title'),
lang('Episode.form.show_notes_section_subtitle'),
) ?>
<div class="mb-4">
<?= form_label(lang('Episode.form.description'), 'description') ?>
<?= form_textarea(
[
'id' => 'description',
'name' => 'description',
'class' => 'form-textarea',
'required' => 'required',
],
old('description', '', false),
'data-editor="markdown"',
) ?>
</div>
<div class="mb-4">
<?= form_label(
lang('Episode.form.description_footer'),
'description_footer',
[],
lang('Episode.form.description_footer_hint'),
) ?>
<?= form_textarea(
[
'id' => 'description_footer',
'name' => 'description_footer',
'class' => 'form-textarea',
],
old(
'description_footer',
$podcast->episode_description_footer_markdown ?? '',
false,
),
'data-editor="markdown"',
) ?>
</div>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.location_section_title'),
lang('Episode.form.location_section_subtitle'),
) ?>
<?= form_label(
lang('Episode.form.location_name'),
'location_name',
[],
lang('Episode.form.location_name_hint'),
true,
) ?>
<?= form_input([
'id' => 'location_name',
'name' => 'location_name',
'class' => 'form-input mb-4',
'value' => old('location_name'),
]) ?>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.additional_files_section_title'),
lang('Episode.form.additional_files_section_subtitle'),
) ?>
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
<legend><?= lang('Episode.form.transcript') .
'<small class="ml-1 lowercase">(' .
lang('Common.optional') .
')</small>' .
hint_tooltip(lang('Episode.form.transcript_hint'), 'ml-1') ?></legend>
<div class="mb-4 form-input-tabs">
<input type="radio" name="transcript-choice" id="transcript-file-upload-choice" aria-controls="transcript-file-upload-choice" value="upload-file" <?= old(
'transcript-choice',
) !== 'remote-url'
? 'checked'
: '' ?> />
<label for="transcript-file-upload-choice"><?= lang(
'Common.forms.upload_file',
) ?></label>
<input type="radio" name="transcript-choice" id="transcript-file-remote-url-choice" aria-controls="transcript-file-remote-url-choice" value="remote-url" <?= old(
'transcript-choice',
) === 'remote-url'
? 'checked'
: '' ?> />
<label for="transcript-file-remote-url-choice"><?= lang(
'Common.forms.remote_url',
) ?></label>
<div class="py-2 tab-panels">
<section id="transcript-file-upload" class="flex items-center tab-panel">
<?= form_label(
lang('Episode.form.transcript_file'),
'transcript_file',
['class' => 'sr-only'],
lang('Episode.form.transcript_file'),
true,
) ?>
<?= form_input([
'id' => 'transcript_file',
'name' => 'transcript_file',
'class' => 'form-input',
'type' => 'file',
'accept' => '.txt,.html,.srt,.json',
]) ?>
</section>
<section id="transcript-file-remote-url" class="tab-panel">
<?= form_label(
lang('Episode.form.transcript_file_remote_url'),
'transcript_file_remote_url',
['class' => 'sr-only'],
lang('Episode.form.transcript_file_remote_url'),
true,
) ?>
<?= form_input([
'id' => 'transcript_file_remote_url',
'name' => 'transcript_file_remote_url',
'class' => 'form-input w-full',
'type' => 'url',
'placeholder' => 'https://...',
'value' => old('transcript_file_remote_url'),
]) ?>
</section>
</div>
</div>
<?= form_fieldset_close() ?>
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
<legend><?= lang('Episode.form.chapters') .
'<small class="ml-1 lowercase">(' .
lang('Common.optional') .
')</small>' .
hint_tooltip(lang('Episode.form.chapters_hint'), 'ml-1') ?></legend>
<div class="mb-4 form-input-tabs">
<input type="radio" name="chapters-choice" id="chapters-file-upload-choice" aria-controls="chapters-file-upload-choice" value="upload-file" <?= old(
'chapters-choice',
) !== 'remote-url'
? 'checked'
: '' ?> />
<label for="chapters-file-upload-choice"><?= lang(
'Common.forms.upload_file',
) ?></label>
<input type="radio" name="chapters-choice" id="chapters-file-remote-url-choice" aria-controls="chapters-file-remote-url-choice" value="remote-url" <?= old(
'chapters-choice',
) === 'remote-url'
? 'checked'
: '' ?> />
<label for="chapters-file-remote-url-choice"><?= lang(
'Common.forms.remote_url',
) ?></label>
<div class="py-2 tab-panels">
<section id="chapters-file-upload" class="flex items-center tab-panel">
<?= form_label(
lang('Episode.form.chapters_file'),
'chapters_file',
['class' => 'sr-only'],
lang('Episode.form.chapters_file'),
true,
) ?>
<?= form_input([
'id' => 'chapters_file',
'name' => 'chapters_file',
'class' => 'form-input',
'type' => 'file',
'accept' => '.json',
]) ?>
</section>
<section id="chapters-file-remote-url" class="tab-panel">
<?= form_label(
lang('Episode.form.chapters_file_remote_url'),
'chapters_file_remote_url',
['class' => 'sr-only'],
lang('Episode.form.chapters_file_remote_url'),
true,
) ?>
<?= form_input([
'id' => 'chapters_file_remote_url',
'name' => 'chapters_file_remote_url',
'class' => 'form-input w-full',
'type' => 'url',
'placeholder' => 'https://...',
'value' => old('chapters_file_remote_url'),
]) ?>
</section>
</div>
</div>
<?= form_fieldset_close() ?>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.advanced_section_title'),
lang('Episode.form.advanced_section_subtitle'),
) ?>
<?= form_label(
lang('Episode.form.custom_rss'),
'custom_rss',
[],
lang('Episode.form.custom_rss_hint'),
true,
) ?>
<?= form_textarea([
'id' => 'custom_rss',
'name' => 'custom_rss',
'class' => 'form-textarea',
'value' => old('custom_rss'),
]) ?>
<?= form_section_close() ?>
<?= form_switch(
lang('Episode.form.block') .
hint_tooltip(lang('Episode.form.block_hint'), 'ml-1'),
['id' => 'block', 'name' => 'block'],
'yes',
old('block', false),
) ?>
<?= button(
lang('Episode.form.submit_create'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Episode.edit') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Episode.edit') ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_open_multipart(route_to('episode-edit', $podcast->id, $episode->id), [
'method' => 'post',
'class' => 'flex flex-col',
]) ?>
<?= csrf_field() ?>
<div class="inline-flex w-full p-2 mb-4 text-sm font-semibold text-yellow-800 bg-red-100 border border-red-300 rounded" role="alert">
<?= icon('alert', 'mr-2 text-lg flex-shrink-0') .
lang('Episode.form.warning') ?>
</div>
<?= form_section(
lang('Episode.form.info_section_title'),
'<img
src="' .
$episode->image->medium_url .
'"
alt="' .
$episode->title .
'"
class="w-48"
/>',
) ?>
<?= form_label(
lang('Episode.form.audio_file'),
'audio_file',
[],
lang('Episode.form.audio_file_hint'),
) ?>
<?= form_input([
'id' => 'audio_file',
'name' => 'audio_file',
'class' => 'form-input mb-4',
'type' => 'file',
'accept' => '.mp3,.m4a',
]) ?>
<?= form_label(
lang('Episode.form.image'),
'image',
[],
lang('Episode.form.image_hint'),
true,
) ?>
<?= form_input([
'id' => 'image',
'name' => 'image',
'class' => 'form-input',
'type' => 'file',
'accept' => '.jpg,.jpeg,.png',
]) ?>
<small class="mb-4 text-gray-600"><?= lang(
'Common.forms.image_size_hint',
) ?></small>
<?= form_label(
lang('Episode.form.title'),
'title',
[],
lang('Episode.form.title_hint'),
) ?>
<?= form_input([
'id' => 'title',
'name' => 'title',
'class' => 'form-input mb-4',
'value' => old('title', $episode->title),
'required' => 'required',
'data-slugify' => 'title',
]) ?>
<?= form_label(
lang('Episode.form.slug'),
'slug',
[],
lang('Episode.form.slug_hint'),
) ?>
<?= form_input([
'id' => 'slug',
'name' => 'slug',
'class' => 'form-input mb-4',
'value' => old('slug', $episode->slug),
'required' => 'required',
'data-slugify' => 'slug',
]) ?>
<div class="flex flex-col mb-4 gap-x-2 gap-y-4 md:flex-row">
<div class="flex flex-col flex-1">
<?= form_label(lang('Episode.form.season_number'), 'season_number') ?>
<?= form_input([
'id' => 'season_number',
'name' => 'season_number',
'class' => 'form-input w-full',
'value' => old('season_number', $episode->season_number),
'type' => 'number',
]) ?>
</div>
<div class="flex flex-col flex-1">
<?= form_label(lang('Episode.form.episode_number'), 'episode_number') ?>
<?= form_input([
'id' => 'episode_number',
'name' => 'episode_number',
'class' => 'form-input w-full',
'value' => old('episode_number', $episode->number),
'type' => 'number',
]) ?>
</div>
</div>
<?= form_fieldset('', ['class' => 'flex mb-4 gap-1']) ?>
<legend>
<?= lang('Episode.form.type.label') .
hint_tooltip(lang('Episode.form.type.hint'), 'ml-1') ?>
</legend>
<?= form_radio(
['id' => 'full', 'name' => 'type', 'class' => 'form-radio-btn'],
'full',
old('type') ? old('type') === 'full' : $episode->type === 'full',
) ?>
<label for="full" class="inline-flex items-center">
<?= lang('Episode.form.type.full') ?>
</label>
<?= form_radio(
['id' => 'trailer', 'name' => 'type', 'class' => 'form-radio-btn'],
'trailer',
old('type') ? old('type') === 'trailer' : $episode->type === 'trailer',
) ?>
<label for="trailer" class="inline-flex items-center">
<?= lang('Episode.form.type.trailer') ?>
</label>
<?= form_radio(
['id' => 'bonus', 'name' => 'type', 'class' => 'form-radio-btn'],
'bonus',
old('type') ? old('type') === 'bonus' : $episode->type === 'bonus',
) ?>
<label for="bonus" class="inline-flex items-center">
<?= lang('Episode.form.type.bonus') ?>
</label>
<?= form_fieldset_close() ?>
<?= form_fieldset('', ['class' => 'mb-6']) ?>
<legend>
<?= lang('Episode.form.parental_advisory.label') .
hint_tooltip(lang('Episode.form.parental_advisory.hint'), 'ml-1') ?>
</legend>
<?= form_radio(
[
'id' => 'undefined',
'name' => 'parental_advisory',
'class' => 'form-radio-btn',
],
'undefined',
old('parental_advisory')
? old('parental_advisory') === 'undefined'
: $episode->parental_advisory === null,
) ?>
<label for="undefined"><?= lang(
'Episode.form.parental_advisory.undefined',
) ?></label>
<?= form_radio(
[
'id' => 'clean',
'name' => 'parental_advisory',
'class' => 'form-radio-btn',
],
'clean',
old('parental_advisory')
? old('parental_advisory') === 'clean'
: $episode->parental_advisory === 'clean',
) ?>
<label for="clean"><?= lang(
'Episode.form.parental_advisory.clean',
) ?></label>
<?= form_radio(
[
'id' => 'explicit',
'name' => 'parental_advisory',
'class' => 'form-radio-btn',
],
'explicit',
old('parental_advisory')
? old('parental_advisory') === 'explicit'
: $episode->parental_advisory === 'explicit',
) ?>
<label for="explicit"><?= lang(
'Episode.form.parental_advisory.explicit',
) ?></label>
<?= form_fieldset_close() ?>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.show_notes_section_title'),
lang('Episode.form.show_notes_section_subtitle'),
) ?>
<div class="mb-4">
<?= form_label(lang('Episode.form.description'), 'description') ?>
<?= form_textarea(
[
'id' => 'description',
'name' => 'description',
'class' => 'form-textarea',
'required' => 'required',
],
old('description', $episode->description_markdown, false),
'data-editor="markdown"',
) ?>
</div>
<div class="mb-4">
<?= form_label(
lang('Episode.form.description_footer'),
'description_footer',
[],
lang('Episode.form.description_footer_hint'),
) ?>
<?= form_textarea(
[
'id' => 'description_footer',
'name' => 'description_footer',
'class' => 'form-textarea',
],
old(
'description_footer',
$podcast->episode_description_footer_markdown ?? '',
false,
),
'data-editor="markdown"',
) ?>
</div>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.location_section_title'),
lang('Episode.form.location_section_subtitle'),
) ?>
<?= form_label(
lang('Episode.form.location_name'),
'location_name',
[],
lang('Episode.form.location_name_hint'),
true,
) ?>
<?= form_input([
'id' => 'location_name',
'name' => 'location_name',
'class' => 'form-input mb-4',
'value' => old('location_name', $episode->location_name),
]) ?>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.additional_files_section_title'),
lang('Episode.form.additional_files_section_subtitle', [
'podcastNamespaceLink' =>
'“<a href="https://github.com/Podcastindex-org/podcast-namespace" target="_blank" rel="noreferrer noopener" style="text-decoration: underline;">podcast namespace</a>”',
]),
) ?>
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
<legend><?= lang('Episode.form.transcript') .
'<small class="ml-1 lowercase">(' .
lang('Common.optional') .
')</small>' .
hint_tooltip(lang('Episode.form.transcript_hint'), 'ml-1') ?></legend>
<div class="mb-4 form-input-tabs">
<input type="radio" name="transcript-choice" id="transcript-file-upload-choice" aria-controls="transcript-file-upload-choice" value="upload-file" <?= $episode->transcript_file_remote_url
? ''
: 'checked' ?> />
<label for="transcript-file-upload-choice"><?= lang(
'Common.forms.upload_file',
) ?></label>
<input type="radio" name="transcript-choice" id="transcript-file-remote-url-choice" aria-controls="transcript-file-remote-url-choice" value="remote-url" <?= $episode->transcript_file_remote_url
? 'checked'
: '' ?> />
<label for="transcript-file-remote-url-choice"><?= lang(
'Common.forms.remote_url',
) ?></label>
<div class="py-2 tab-panels">
<section id="transcript-file-upload" class="flex items-center tab-panel">
<?php if ($episode->transcript_file): ?>
<div class="flex justify-between">
<?= anchor(
$episode->transcript_file_url,
icon('file', 'mr-2 text-gray-500') .
$episode->transcript_file,
[
'class' => 'inline-flex items-center text-xs',
'target' => '_blank',
'rel' => 'noreferrer noopener',
],
) .
anchor(
route_to(
'transcript-delete',
$podcast->id,
$episode->id,
),
icon('delete-bin', 'mx-auto'),
[
'class' =>
'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900',
'data-toggle' => 'tooltip',
'data-placement' => 'bottom',
'title' => lang(
'Episode.form.transcript_file_delete',
),
],
) ?>
</div>
<?php endif; ?>
<?= form_label(
lang('Episode.form.transcript_file'),
'transcript_file',
['class' => 'sr-only'],
lang('Episode.form.transcript_file'),
true,
) ?>
<?= form_input([
'id' => 'transcript_file',
'name' => 'transcript_file',
'class' => 'form-input',
'type' => 'file',
'accept' => '.txt,.html,.srt,.json',
]) ?>
</section>
<section id="transcript-file-remote-url" class="tab-panel">
<?= form_label(
lang('Episode.form.transcript_file_remote_url'),
'transcript_file_remote_url',
['class' => 'sr-only'],
lang('Episode.form.transcript_file_remote_url'),
true,
) ?>
<?= form_input([
'id' => 'transcript_file_remote_url',
'name' => 'transcript_file_remote_url',
'class' => 'form-input w-full',
'type' => 'url',
'placeholder' => 'https://...',
'value' => old(
'transcript_file_remote_url',
$episode->transcript_file_remote_url,
),
]) ?>
</section>
</div>
</div>
<?= form_fieldset_close() ?>
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
<legend><?= lang('Episode.form.chapters') .
'<small class="ml-1 lowercase">(' .
lang('Common.optional') .
')</small>' .
hint_tooltip(lang('Episode.form.chapters_hint'), 'ml-1') ?></legend>
<div class="mb-4 form-input-tabs">
<input type="radio" name="chapters-choice" id="chapters-file-upload-choice" aria-controls="chapters-file-upload-choice" value="upload-file" <?= $episode->chapters_file_remote_url
? ''
: 'checked' ?> />
<label for="chapters-file-upload-choice"><?= lang(
'Common.forms.upload_file',
) ?></label>
<input type="radio" name="chapters-choice" id="chapters-file-remote-url-choice" aria-controls="chapters-file-remote-url-choice" value="remote-url" <?= $episode->chapters_file_remote_url
? 'checked'
: '' ?> />
<label for="chapters-file-remote-url-choice"><?= lang(
'Common.forms.remote_url',
) ?></label>
<div class="py-2 tab-panels">
<section id="chapters-file-upload" class="flex items-center tab-panel">
<?php if ($episode->chapters_file): ?>
<div class="flex justify-between">
<?= anchor(
$episode->chapters_file_url,
icon('file', 'mr-2') . $episode->chapters_file,
[
'class' => 'inline-flex items-center text-xs',
'target' => '_blank',
'rel' => 'noreferrer noopener',
],
) .
anchor(
route_to(
'chapters-delete',
$podcast->id,
$episode->id,
),
icon('delete-bin', 'mx-auto'),
[
'class' =>
'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900',
'data-toggle' => 'tooltip',
'data-placement' => 'bottom',
'title' => lang(
'Episode.form.chapters_file_delete',
),
],
) ?>
</div>
<?php endif; ?>
<?= form_label(
lang('Episode.form.chapters_file'),
'chapters_file',
['class' => 'sr-only'],
lang('Episode.form.chapters_file'),
true,
) ?>
<?= form_input([
'id' => 'chapters_file',
'name' => 'chapters_file',
'class' => 'form-input',
'type' => 'file',
'accept' => '.json',
]) ?>
</section>
<section id="chapters-file-remote-url" class="tab-panel">
<?= form_label(
lang('Episode.form.chapters_file_remote_url'),
'chapters_file_remote_url',
['class' => 'sr-only'],
lang('Episode.form.chapters_file_remote_url'),
true,
) ?>
<?= form_input([
'id' => 'chapters_file_remote_url',
'name' => 'chapters_file_remote_url',
'class' => 'form-input w-full',
'type' => 'url',
'placeholder' => 'https://...',
'value' => old(
'chapters_file_remote_url',
$episode->chapters_file_remote_url,
),
]) ?>
</section>
</div>
</div>
<?= form_fieldset_close() ?>
<?= form_section_close() ?>
<?= form_section(
lang('Episode.form.advanced_section_title'),
lang('Episode.form.advanced_section_subtitle'),
) ?>
<?= form_label(
lang('Episode.form.custom_rss'),
'custom_rss',
[],
lang('Episode.form.custom_rss_hint'),
true,
) ?>
<?= form_textarea([
'id' => 'custom_rss',
'name' => 'custom_rss',
'class' => 'form-textarea',
'value' => old('custom_rss', $episode->custom_rss_string),
]) ?>
<?= form_section_close() ?>
<?= form_switch(
lang('Episode.form.block') .
hint_tooltip(lang('Episode.form.block_hint'), 'ml-1'),
['id' => 'block', 'name' => 'block'],
'yes',
old('block', $episode->is_blocked),
) ?>
<?= button(
lang('Episode.form.submit_edit'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Episode.embeddable_player.title') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Episode.embeddable_player.title') ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_label(lang('Episode.embeddable_player.label'), 'label') ?>
<div class="flex w-full mt-6 mb-6">
<?php foreach ($themes as $themeKey => $theme): ?>
<button style="<?= $theme[
'style'
] ?>" class="w-12 h-12 mr-1 border-2 border-gray-400 rounded-lg hover:border-white" title="<?= lang(
"Episode.embeddable_player.{$themeKey}",
) ?>" data-type="theme-picker" data-url="<?= $episode->getEmbeddablePlayerUrl(
$themeKey,
) ?>"></button>
<?php endforeach; ?>
</div>
<iframe name="embeddable_player" id="embeddable_player" class="w-full h-48 max-w-xl" frameborder="0" scrolling="no" style="width: 100%; overflow: hidden;" src="<?= $episode->embeddable_player_url ?>"></iframe>
<div class="flex items-center w-full mt-8">
<?= form_textarea(
[
'id' => 'iframe',
'name' => 'iframe',
'class' => 'form-textarea w-full h-20 mr-2',
],
"<iframe width=\"100%\" height=\"280\" frameborder=\"0\" scrolling=\"no\" style=\"width: 100%; height: 280px; overflow: hidden;\" src=\"{$episode->embeddable_player_url}\"></iframe>",
) ?>
<?= icon_button(
'file-copy',
lang('Episode.embeddable_player.clipboard_iframe'),
'',
['variant' => 'default'],
['data-type' => 'clipboard-copy', 'data-clipboard-target' => 'iframe'],
) ?>
</div>
<div class="flex items-center w-full mt-4">
<?= form_textarea(
[
'id' => 'url',
'name' => 'url',
'class' => 'form-textarea w-full h-10 mr-2',
],
$episode->embeddable_player_url,
) ?>
<?= icon_button(
'file-copy',
lang('Episode.embeddable_player.clipboard_url'),
'',
['variant' => 'default'],
['data-type' => 'clipboard-copy', 'data-clipboard-target' => 'url'],
) ?>
</div>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Episode.all_podcast_episodes') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Episode.all_podcast_episodes') ?> (<?= $pager->getDetails()[
'total'
] ?>)
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(lang('Episode.create'), route_to('episode-create', $podcast->id), [
'variant' => 'accent',
'iconLeft' => 'add',
]) ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<p class="mb-4 text-sm italic text-gray-700"><?= lang('Common.pageInfo', [
'currentPage' => $pager->getDetails()['currentPage'],
'pageCount' => $pager->getDetails()['pageCount'],
]) ?></p>
<div class="flex flex-wrap mb-6">
<?php if ($episodes): ?>
<?php foreach ($episodes as $episode): ?>
<article class="flex w-full max-w-lg p-4 mx-auto">
<img
loading="lazy"
src="<?= $episode->image->thumbnail_url ?>"
alt="<?= $episode->title ?>" class="object-cover w-20 h-20 mr-2 rounded-lg" />
<div class="flex flex-col flex-1">
<div class="flex">
<a class="flex-1 text-sm hover:underline" href="<?= route_to(
'episode-view',
$podcast->id,
$episode->id,
) ?>">
<h2 class="inline-flex justify-between w-full font-semibold leading-none group">
<span class="mr-1 group-hover:underline"><?= $episode->title ?></span>
<?= episode_numbering(
$episode->number,
$episode->season_number,
'text-xs font-semibold text-gray-600',
true,
) ?>
</h2>
</a>
<button
id="more-dropdown-<?= $episode->id ?>"
type="button"
class="inline-flex items-center p-1 outline-none focus:ring"
data-dropdown="button"
data-dropdown-target="more-dropdown-<?= $episode->id ?>-menu"
aria-haspopup="true"
aria-expanded="false">
<?= icon('more') ?>
</button>
<nav
id="more-dropdown-<?= $episode->id ?>-menu"
class="flex flex-col py-2 text-black whitespace-no-wrap bg-white border rounded shadow"
aria-labelledby="more-dropdown-<?= $episode->id ?>"
data-dropdown="menu"
data-dropdown-placement="bottom-start"
data-dropdown-offset-x="0"
data-dropdown-offset-y="-24">
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'episode-edit',
$podcast->id,
$episode->id,
) ?>"><?= lang('Episode.edit') ?></a>
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'embeddable-player-add',
$podcast->id,
$episode->id,
) ?>"><?= lang(
'Episode.embeddable_player.add',
) ?></a>
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'episode-person-manage',
$podcast->id,
$episode->id,
) ?>"><?= lang('Person.persons') ?></a>
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'soundbites-edit',
$podcast->id,
$episode->id,
) ?>"><?= lang('Episode.soundbites') ?></a>
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'episode',
$podcast->name,
$episode->slug,
) ?>"><?= lang('Episode.go_to_page') ?></a>
<a class="px-4 py-1 hover:bg-gray-100" href="<?= route_to(
'episode-delete',
$podcast->id,
$episode->id,
) ?>"><?= lang('Episode.delete') ?></a>
</nav>
</div>
<div class="mb-2 text-xs">
<?= publication_pill(
$episode->published_at,
$episode->publication_status,
) ?>
<span class="mx-1"></span>
<time datetime="PT<?= $episode->audio_file_duration ?>S">
<?= format_duration(
$episode->audio_file_duration,
) ?>
</time>
</div>
<audio controls preload="none" class="w-full mt-auto">
<source src="<?= $episode->audio_file_url ?>" type="<?= $episode->audio_file_mimetype ?>">
Your browser does not support the audio tag.
</audio>
</div>
</article>
<?php endforeach; ?>
<?php else: ?>
<p class="italic"><?= lang('Podcast.no_episode') ?></p>
<?php endif; ?>
</div>
<?= $pager->links() ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Episode.publish') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Episode.publish') ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_open(route_to('episode-publish', $podcast->id, $episode->id), [
'method' => 'post',
'class' => 'flex flex-col max-w-xl items-start',
]) ?>
<?= csrf_field() ?>
<?= form_hidden('client_timezone', 'UTC') ?>
<label for="message" class="text-lg font-semibold"><?= lang(
'Episode.publish_form.note',
) . hint_tooltip(lang('Episode.publish_form.note_hint'), 'ml-1') ?></label>
<div class="mb-8 overflow-hidden bg-white shadow-md rounded-xl">
<div class="flex px-4 py-3">
<img src="<?= $podcast->actor->avatar_image_url ?>" alt="<?= $podcast
->actor->display_name ?>" class="w-12 h-12 mr-4 rounded-full"/>
<p class="flex items-baseline min-w-0">
<span class="mr-2 font-semibold truncate"><?= $podcast->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $podcast->actor
->username ?></span>
</p>
</div>
<div class="px-4 mb-2">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea min-w-0 w-full',
'required' => 'required',
'placeholder' => 'Write your message...',
],
old('message', '', false),
['rows' => 2],
) ?>
</div>
<div class="flex">
<img
src="<?= $episode->image->thumbnail_url ?>"
alt="<?= $episode->title ?>" class="w-24 h-24"/>
<div class="flex flex-col flex-1">
<a href="<?= $episode->link ?>" class="flex-1 px-4 py-2 bg-gray-100">
<div class="flex items-baseline">
<span class="flex-1 w-0 mr-2 text-sm font-semibold truncate"><?= $episode->title ?></span>
<?= episode_numbering(
$episode->number,
$episode->season_number,
'text-xs font-semibold text-gray-600',
true,
) ?>
</div>
<div class="text-xs text-gray-600">
<time datetime="PT<?= $episode->audio_file_duration ?>S">
<?= format_duration($episode->audio_file_duration) ?>
</time>
</div>
</a>
<audio controls preload="none" class="w-full mt-auto">
<source
src="<?= $episode->audio_file_url ?>"
type="<?= $episode->audio_file_mimetype ?>">
Your browser does not support the audio tag.
</audio>
</div>
</div>
<footer class="flex justify-around px-6 py-3">
<span class="inline-flex items-center"><?= icon(
'chat',
'text-xl mr-1 text-gray-400',
) . '0' ?></span>
<span class="inline-flex items-center"><?= icon(
'repeat',
'text-xl mr-1 text-gray-400',
) . '0' ?></span>
<span class="inline-flex items-center"><?= icon(
'heart',
'text-xl mr-1 text-gray-400',
) . '0' ?></span>
</footer>
</div>
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
<legend class="text-lg font-semibold"><?= lang(
'Episode.publish_form.publication_date',
) ?></legend>
<label for="now" class="inline-flex items-center">
<?= form_radio(
[
'id' => 'now',
'name' => 'publication_method',
'class' => 'text-pine-700',
],
'now',
old('publication_method') ? old('publish') === 'now' : true,
) ?>
<span class="ml-2"><?= lang(
'Episode.publish_form.publication_method.now',
) ?></span>
</label>
<div class="inline-flex flex-wrap items-center mb-4 radio-toggler">
<?= form_radio(
[
'id' => 'schedule',
'name' => 'publication_method',
'class' => 'text-pine-700',
],
'schedule',
old('publication_method') &&
old('publication_method') === 'schedule',
) ?>
<label for="schedule" class="ml-2"><?= lang(
'Episode.publish_form.publication_method.schedule',
) ?></label>
<div class="w-full mt-2 radio-toggler-element">
<?= form_label(
lang('Episode.publish_form.scheduled_publication_date'),
'scheduled_publication_date',
[],
lang('Episode.publish_form.scheduled_publication_date_hint'),
) ?>
<div class="flex mb-4" data-picker="datetime">
<?= form_input([
'id' => 'scheduled_publication_date',
'name' => 'scheduled_publication_date',
'class' => 'form-input rounded-r-none flex-1',
'value' => old('scheduled_publication_date', ''),
'data-input' => '',
]) ?>
<button
class="p-3 border border-l-0 border-gray-500 bg-pine-100 focus:outline-none rounded-r-md hover:bg-pine-200 focus:ring"
type="button"
title="<?= lang(
'Episode.publish_form.scheduled_publication_date_clear',
) ?>"
data-clear=""><?= icon('close') ?></button>
</div>
</div>
</div>
<?= form_fieldset_close() ?>
<div class="self-end">
<?= anchor(
route_to('episode-view', $podcast->id, $episode->id),
lang('Common.cancel'),
['class' => 'font-semibold mr-4'],
) ?>
<?= button(
lang('Episode.publish_form.submit'),
'',
['variant' => 'primary'],
['type' => 'submit'],
) ?>
</div>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Episode.publish') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Episode.publish') ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_open(route_to('episode-publish_edit', $podcast->id, $episode->id), [
'method' => 'post',
'class' => 'flex flex-col max-w-xl items-start',
]) ?>
<?= csrf_field() ?>
<?= form_hidden('client_timezone', 'UTC') ?>
<?= form_hidden('note_id', $note->id) ?>
<label for="message" class="text-lg font-semibold"><?= lang(
'Episode.publish_form.note',
) . hint_tooltip(lang('Episode.publish_form.note_hint'), 'ml-1') ?></label>
<div class="mb-8 overflow-hidden bg-white shadow-md rounded-xl">
<div class="flex px-4 py-3">
<img src="<?= $podcast->actor->avatar_image_url ?>" alt="<?= $podcast->actor
->display_name ?>" class="w-12 h-12 mr-4 rounded-full"/>
<div class="flex flex-col min-w-0">
<p class="flex items-baseline min-w-0">
<span class="mr-2 font-semibold truncate"><?= $podcast->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $podcast
->actor->username ?></span>
</p>
<time class="text-xs text-gray-500" itemprop="published" datetime="<?= $note->published_at->format(
DateTime::ATOM,
) ?>" title="<?= $note->published_at ?>"><?= lang(
'Common.mediumDate',
[$note->published_at],
) ?></time>
</div>
</div>
<div class="px-4 mb-2">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea',
'required' => 'required',
'placeholder' => 'Write your message...',
],
old('message', $note->message, false),
['rows' => 2],
) ?>
</div>
<div class="flex">
<img src="<?= $episode->image
->thumbnail_url ?>" alt="<?= $episode->title ?>" class="w-24 h-24" />
<div class="flex flex-col flex-1">
<a href="<?= $episode->link ?>" class="flex-1 px-4 py-2 bg-gray-100">
<div class="flex items-baseline">
<span class="flex-1 w-0 mr-2 text-sm font-semibold truncate"><?= $episode->title ?></span>
<?= episode_numbering(
$episode->number,
$episode->season_number,
'text-xs font-semibold text-gray-600',
true,
) ?>
</div>
<div class="text-xs text-gray-600">
<time itemprop="published" datetime="<?= $episode->published_at->format(
DateTime::ATOM,
) ?>" title="<?= $episode->published_at ?>">
<?= lang('Common.mediumDate', [
$episode->published_at,
]) ?>
</time>
<span class="mx-1"></span>
<time datetime="PT<?= $episode->audio_file_duration ?>S">
<?= format_duration($episode->audio_file_duration) ?>
</time>
</div>
</a>
<audio controls preload="none" class="w-full mt-auto">
<source src="<?= $episode->audio_file_url ?>" type="<?= $episode->audio_file_mimetype ?>">
Your browser does not support the audio tag.
</audio>
</div>
</div>
<footer class="flex justify-around px-6 py-3">
<span class="inline-flex items-center"><?= icon(
'chat',
'text-xl mr-1 text-gray-400',
) . '0' ?></span>
<span class="inline-flex items-center"><?= icon(
'repeat',
'text-xl mr-1 text-gray-400',
) . '0' ?></span>
<span class="inline-flex items-center"><?= icon(
'heart',
'text-xl mr-1 text-gray-400',
) . '0' ?></span>
</footer>
</div>
<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
<legend class="text-lg font-semibold"><?= lang(
'Episode.publish_form.publication_date',
) ?></legend>
<label for="now" class="inline-flex items-center">
<?= form_radio(
[
'id' => 'now',
'name' => 'publication_method',
'class' => 'text-pine-700',
],
'now',
old('publication_method') && old('publish') === 'now',
) ?>
<span class="ml-2"><?= lang(
'Episode.publish_form.publication_method.now',
) ?></span>
</label>
<div class="inline-flex flex-wrap items-center mb-4 radio-toggler">
<?= form_radio(
[
'id' => 'schedule',
'name' => 'publication_method',
'class' => 'text-pine-700',
],
'schedule',
old('publication_method')
? old('publication_method') === 'schedule'
: true,
) ?>
<label for="schedule" class="ml-2"><?= lang(
'Episode.publish_form.publication_method.schedule',
) ?></label>
<div class="w-full mt-2 radio-toggler-element">
<?= form_label(
lang('Episode.publish_form.scheduled_publication_date'),
'scheduled_publication_date',
[],
lang('Episode.publish_form.scheduled_publication_date_hint'),
) ?>
<div class="flex mb-4" data-picker="datetime">
<?= form_input([
'id' => 'scheduled_publication_date',
'name' => 'scheduled_publication_date',
'class' => 'form-input rounded-r-none flex-1',
'value' => old(
'scheduled_publication_date',
$episode->published_at,
),
'data-input' => '',
]) ?>
<button class="p-3 border border-l-0 border-gray-500 bg-pine-100 focus:outline-none rounded-r-md hover:bg-pine-200 focus:ring" type="button" aria-label="<?= lang(
'Episode.publish_form.scheduled_publication_date_clear',
) ?>" title="<?= lang(
'Episode.publish_form.scheduled_publication_date_clear',
) ?>" data-clear=""><?= icon('close') ?></button>
</div>
</div>
</div>
<?= form_fieldset_close() ?>
<div class="self-end">
<?= anchor(
route_to('episode-view', $podcast->id, $episode->id),
lang('Common.cancel'),
['class' => 'font-semibold mr-4'],
) ?>
<?= button(
lang('Episode.publish_form.submit_edit'),
'',
['variant' => 'primary'],
['type' => 'submit'],
) ?>
</div>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('admin/_layout') ?>
<?= $this->section('title') ?>
<?= lang('Episode.soundbites_form.title') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Episode.soundbites_form.title') ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<?= form_open_multipart(
route_to('episode-soundbites-edit', $podcast->id, $episode->id),
['method' => 'post', 'class' => 'flex flex-col'],
) ?>
<?= csrf_field() ?>
<?= form_section(
lang('Episode.soundbites_form.info_section_title'),
lang('Episode.soundbites_form.info_section_subtitle'),
) ?>
<table class="w-full table-fixed">
<thead>
<tr>
<th class="w-3/12 px-1 py-2">
<?= form_label(
lang('Episode.soundbites_form.start_time'),
'start_time',
[],
lang('Episode.soundbites_form.start_time_hint'),
) ?></th>
<th class="w-3/12 px-1 py-2"><?= form_label(
lang('Episode.soundbites_form.duration'),
'duration',
[],
lang('Episode.soundbites_form.duration_hint'),
) ?></th>
<th class="w-7/12 px-1 py-2"><?= form_label(
lang('Episode.soundbites_form.label'),
'label',
[],
lang('Episode.soundbites_form.label_hint'),
true,
) ?></th>
<th class="w-1/12 px-1 py-2"></th>
</tr>
</thead>
<tbody>
<?php foreach ($episode->soundbites as $soundbite): ?>
<tr>
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => "soundbites[{$soundbite->id}][start_time]",
'name' => "soundbites[{$soundbite->id}][start_time]",
'class' => 'form-input w-full border-none text-center',
'value' => $soundbite->start_time,
'data-type' => 'soundbite-field',
'data-field-type' => 'start-time',
'data-soundbite-id' => $soundbite->id,
'required' => 'required',
],
) ?></td>
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => "soundbites[{$soundbite->id}][duration]",
'name' => "soundbites[{$soundbite->id}][duration]",
'class' => 'form-input w-full border-none text-center',
'value' => $soundbite->duration,
'data-type' => 'soundbite-field',
'data-field-type' => 'duration',
'data-soundbite-id' => $soundbite->id,
'required' => 'required',
],
) ?></td>
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'id' => "soundbites[{$soundbite->id}][label]",
'name' => "soundbites[{$soundbite->id}][label]",
'class' => 'form-input w-full border-none',
'value' => $soundbite->label,
],
) ?></td>
<td class="px-4 py-2"><?= icon_button(
'play',
lang('Episode.soundbites_form.play'),
'',
['variant' => 'primary'],
[
'class' => 'mb-1 mr-1',
'data-type' => 'play-soundbite',
'data-soundbite-id' => $soundbite->id,
'data-soundbite-start-time' => $soundbite->start_time,
'data-soundbite-duration' => $soundbite->duration,
],
) ?>
<?= icon_button(
'delete-bin',
lang('Episode.soundbites_form.delete'),
route_to(
'soundbite-delete',
$podcast->id,
$episode->id,
$soundbite->id,
),
['variant' => 'danger'],
[],
) ?>
</td>
</tr>
<?php endforeach; ?>
<tr>
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => 'soundbites[0][start_time]',
'name' => 'soundbites[0][start_time]',
'class' => 'form-input w-full border-none text-center',
'value' => old('start_time'),
'data-soundbite-id' => '0',
'data-type' => 'soundbite-field',
'data-field-type' => 'start-time',
],
) ?></td>
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => 'soundbites[0][duration]',
'name' => 'soundbites[0][duration]',
'class' => 'form-input w-full border-none text-center',
'value' => old('duration'),
'data-soundbite-id' => '0',
'data-type' => 'soundbite-field',
'data-field-type' => 'duration',
],
) ?></td>
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'id' => 'soundbites[0][label]',
'name' => 'soundbites[0][label]',
'class' => 'form-input w-full border-none',
'value' => old('label'),
],
) ?></td>
<td class="px-4 py-2"><?= icon_button(
'play',
lang('Episode.soundbites_form.play'),
'',
['variant' => 'primary'],
[
'data-type' => 'play-soundbite',
'data-soundbite-id' => 0,
'data-soundbite-start-time' => 0,
'data-soundbite-duration' => 0,
],
) ?>
</td>
</tr>
<tr><td colspan="3">
<audio controls preload="auto" class="w-full">
<source src="<?= $episode->audio_file_url ?>" type="<?= $episode->audio_file_mimetype ?>">
Your browser does not support the audio tag.
</audio>
</td><td class="px-4 py-2"><?= icon_button(
'timer',
lang('Episode.soundbites_form.bookmark'),
'',
['variant' => 'info'],
[
'data-type' => 'get-soundbite',
'data-start-time-field-name' => 'soundbites[0][start_time]',
'data-duration-field-name' => 'soundbites[0][duration]',
],
) ?></td></tr>
</tbody>
</table>
<?= form_section_close() ?>
<?= button(
lang('Episode.soundbites_form.submit_edit'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>