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
  • alpha
  • beta
  • develop
  • docs/fix-readme
  • docs/update-vitepress
  • draft/rss-feed
  • feat/dashboard
  • feat/episodes-page-ux
  • feat/generator-user-agent
  • feat/headliner
  • feat/new-languages
  • feat/plugins
  • fix/federation
  • fix/forms-ux
  • i18n
  • main
  • next
  • refactor/transcripts
  • v1.0.0
  • v1.0.0-alpha.1
  • v1.0.0-alpha.10
  • v1.0.0-alpha.11
  • v1.0.0-alpha.12
  • v1.0.0-alpha.13
  • v1.0.0-alpha.14
  • v1.0.0-alpha.15
  • v1.0.0-alpha.16
  • v1.0.0-alpha.17
  • v1.0.0-alpha.18
  • v1.0.0-alpha.19
  • v1.0.0-alpha.2
  • v1.0.0-alpha.20
  • v1.0.0-alpha.21
  • v1.0.0-alpha.22
  • v1.0.0-alpha.23
  • v1.0.0-alpha.24
  • v1.0.0-alpha.25
  • v1.0.0-alpha.26
  • v1.0.0-alpha.27
  • v1.0.0-alpha.28
  • v1.0.0-alpha.29
  • v1.0.0-alpha.3
  • v1.0.0-alpha.30
  • v1.0.0-alpha.31
  • v1.0.0-alpha.32
  • v1.0.0-alpha.33
  • v1.0.0-alpha.34
  • v1.0.0-alpha.35
  • v1.0.0-alpha.36
  • v1.0.0-alpha.37
  • v1.0.0-alpha.38
  • v1.0.0-alpha.39
  • v1.0.0-alpha.4
  • v1.0.0-alpha.40
  • v1.0.0-alpha.41
  • v1.0.0-alpha.42
  • v1.0.0-alpha.43
  • v1.0.0-alpha.44
  • v1.0.0-alpha.45
  • v1.0.0-alpha.46
  • v1.0.0-alpha.47
  • v1.0.0-alpha.48
  • v1.0.0-alpha.49
  • v1.0.0-alpha.5
  • v1.0.0-alpha.50
  • v1.0.0-alpha.51
  • v1.0.0-alpha.52
  • v1.0.0-alpha.53
  • v1.0.0-alpha.54
  • v1.0.0-alpha.55
  • v1.0.0-alpha.56
  • v1.0.0-alpha.57
  • v1.0.0-alpha.58
  • v1.0.0-alpha.59
  • v1.0.0-alpha.6
  • v1.0.0-alpha.60
  • v1.0.0-alpha.61
  • v1.0.0-alpha.62
  • v1.0.0-alpha.63
  • v1.0.0-alpha.64
  • v1.0.0-alpha.65
  • v1.0.0-alpha.66
  • v1.0.0-alpha.67
  • v1.0.0-alpha.68
  • v1.0.0-alpha.69
  • v1.0.0-alpha.7
  • v1.0.0-alpha.70
  • v1.0.0-alpha.71
  • v1.0.0-alpha.72
  • v1.0.0-alpha.73
  • v1.0.0-alpha.74
  • v1.0.0-alpha.75
  • v1.0.0-alpha.76
  • v1.0.0-alpha.77
  • v1.0.0-alpha.78
  • v1.0.0-alpha.79
  • v1.0.0-alpha.8
  • v1.0.0-alpha.80
  • v1.0.0-alpha.9
  • v1.0.0-beta.1
  • v1.0.0-beta.10
  • v1.0.0-beta.11
  • v1.0.0-beta.12
  • v1.0.0-beta.13
  • v1.0.0-beta.14
  • v1.0.0-beta.15
  • v1.0.0-beta.16
  • v1.0.0-beta.17
  • v1.0.0-beta.18
  • v1.0.0-beta.19
  • v1.0.0-beta.2
  • v1.0.0-beta.20
  • v1.0.0-beta.21
  • v1.0.0-beta.22
  • v1.0.0-beta.23
  • v1.0.0-beta.24
  • v1.0.0-beta.3
  • v1.0.0-beta.4
118 results

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
  • alpha
  • beta
  • develop
  • docs/update-vitepress
  • feat/dashboard
  • feat/op3
  • i18n
  • main
  • v1.0.0
  • v1.0.0-alpha.1
  • v1.0.0-alpha.10
  • v1.0.0-alpha.11
  • v1.0.0-alpha.12
  • v1.0.0-alpha.13
  • v1.0.0-alpha.14
  • v1.0.0-alpha.15
  • v1.0.0-alpha.16
  • v1.0.0-alpha.17
  • v1.0.0-alpha.18
  • v1.0.0-alpha.19
  • v1.0.0-alpha.2
  • v1.0.0-alpha.20
  • v1.0.0-alpha.21
  • v1.0.0-alpha.22
  • v1.0.0-alpha.23
  • v1.0.0-alpha.24
  • v1.0.0-alpha.25
  • v1.0.0-alpha.26
  • v1.0.0-alpha.27
  • v1.0.0-alpha.28
  • v1.0.0-alpha.29
  • v1.0.0-alpha.3
  • v1.0.0-alpha.30
  • v1.0.0-alpha.31
  • v1.0.0-alpha.32
  • v1.0.0-alpha.33
  • v1.0.0-alpha.34
  • v1.0.0-alpha.35
  • v1.0.0-alpha.36
  • v1.0.0-alpha.37
  • v1.0.0-alpha.38
  • v1.0.0-alpha.39
  • v1.0.0-alpha.4
  • v1.0.0-alpha.40
  • v1.0.0-alpha.41
  • v1.0.0-alpha.42
  • v1.0.0-alpha.43
  • v1.0.0-alpha.44
  • v1.0.0-alpha.45
  • v1.0.0-alpha.46
  • v1.0.0-alpha.47
  • v1.0.0-alpha.48
  • v1.0.0-alpha.49
  • v1.0.0-alpha.5
  • v1.0.0-alpha.50
  • v1.0.0-alpha.51
  • v1.0.0-alpha.52
  • v1.0.0-alpha.53
  • v1.0.0-alpha.54
  • v1.0.0-alpha.55
  • v1.0.0-alpha.56
  • v1.0.0-alpha.57
  • v1.0.0-alpha.58
  • v1.0.0-alpha.59
  • v1.0.0-alpha.6
  • v1.0.0-alpha.60
  • v1.0.0-alpha.61
  • v1.0.0-alpha.62
  • v1.0.0-alpha.63
  • v1.0.0-alpha.64
  • v1.0.0-alpha.65
  • v1.0.0-alpha.66
  • v1.0.0-alpha.67
  • v1.0.0-alpha.68
  • v1.0.0-alpha.69
  • v1.0.0-alpha.7
  • v1.0.0-alpha.70
  • v1.0.0-alpha.71
  • v1.0.0-alpha.72
  • v1.0.0-alpha.73
  • v1.0.0-alpha.74
  • v1.0.0-alpha.75
  • v1.0.0-alpha.76
  • v1.0.0-alpha.77
  • v1.0.0-alpha.78
  • v1.0.0-alpha.79
  • v1.0.0-alpha.8
  • v1.0.0-alpha.80
  • v1.0.0-alpha.9
  • v1.0.0-beta.1
  • v1.0.0-beta.10
  • v1.0.0-beta.11
  • v1.0.0-beta.12
  • v1.0.0-beta.13
  • v1.0.0-beta.14
  • v1.0.0-beta.15
  • v1.0.0-beta.16
  • v1.0.0-beta.17
  • v1.0.0-beta.18
  • v1.0.0-beta.19
  • v1.0.0-beta.2
  • v1.0.0-beta.20
  • v1.0.0-beta.21
  • v1.0.0-beta.22
  • v1.0.0-beta.23
  • v1.0.0-beta.24
  • v1.0.0-beta.3
  • v1.0.0-beta.4
108 results
Show changes
Showing
with 12 additions and 995 deletions
<?= helper('page') ?>
<!DOCTYPE html>
<html lang="<?= service('request')->getLocale() ?>">
<head>
<meta charset="UTF-8"/>
<title>Castopod</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-pine-50">
<header class="py-8 text-white border-b bg-pine-900">
<div class="container flex items-center justify-between px-2 py-4 mx-auto">
<a href="<?= route_to(
'home',
) ?>" class="inline-flex items-baseline text-3xl font-semibold font-display"><?= 'castopod' .
svg('castopod-logo', 'h-6 ml-2') ?></a>
</div>
</header>
<main class="container flex-1 px-4 py-10 mx-auto">
<h1 class="mb-2 text-xl"><?= lang('Home.all_podcasts') ?> (<?= count(
$podcasts,
) ?>)</h1>
<section class="grid gap-4 grid-cols-podcasts">
<?php if ($podcasts): ?>
<?php foreach ($podcasts as $podcast): ?>
<a href="<?= $podcast->link ?>" class="w-full">
<article class="w-full h-full overflow-hidden bg-white border shadow rounded-xl hover:bg-gray-100 hover:shadow">
<img alt="<?= $podcast->title ?>"
src="<?= $podcast->image->medium_url ?>"
class="object-cover w-full h-48 mb-2" />
<h2 class="px-2 font-semibold leading-tight truncate"><?= $podcast->title ?></h2>
<p class="px-2 pb-2 text-gray-600">@<?= $podcast->name ?></p>
</article>
</a>
<?php endforeach; ?>
<?php else: ?>
<p class="italic"><?= lang('Home.no_podcast') ?></p>
<?php endif; ?>
</section>
</main>
<footer class="container flex justify-between px-2 py-4 mx-auto text-sm text-right border-t">
<?= render_page_links() ?>
<small><?= lang('Common.powered_by', [
'castopod' =>
'<a class="underline hover:no-underline" href="https://castopod.org/" target="_blank" rel="noreferrer noopener">Castopod</a>',
]) ?></small>
</footer>
</body>
<?= $this->extend('install/_layout') ?>
<?= $this->section('content') ?>
<?= form_open(route_to('cache-config'), [
'class' => 'flex flex-col max-w-sm w-full',
]) ?>
<?= csrf_field() ?>
<h1 class="mb-4 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700 font-body">3/4</span><?= lang(
'Install.form.cache_config',
) ?></h1>
<p class="mb-4 text-sm text-gray-600"><?= lang(
'Install.form.cache_config_hint',
) ?></p>
<?= form_label(lang('Install.form.cache_handler'), 'db_prefix') ?>
<?= form_dropdown(
'cache_handler',
[
'file' => lang('Install.form.cacheHandlerOptions.file'),
'redis' => lang('Install.form.cacheHandlerOptions.redis'),
'predis' => lang('Install.form.cacheHandlerOptions.predis'),
],
old('cache_handler', 'file'),
[
'id' => 'cache_handler',
'name' => 'cache_handler',
'class' => 'form-select mb-6',
'value' => config('Database')->default['DBPrefix'],
],
) ?>
<?= button(
lang('Install.form.next') . icon('arrow-right', 'ml-2'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('install/_layout') ?>
<?= $this->section('content') ?>
<?= form_open(route_to('create-superadmin'), [
'class' => 'flex flex-col max-w-sm w-full',
]) ?>
<?= csrf_field() ?>
<h1 class="mb-4 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700 font-body">4/4</span><?= lang(
'Install.form.create_superadmin',
) ?></h1>
<?= form_label(lang('Install.form.email'), 'email') ?>
<?= form_input([
'id' => 'email',
'name' => 'email',
'class' => 'form-input mb-4',
'type' => 'email',
'required' => 'required',
'value' => old('email'),
]) ?>
<?= form_label(lang('Install.form.username'), 'username') ?>
<?= form_input([
'id' => 'username',
'name' => 'username',
'class' => 'form-input mb-4',
'required' => 'required',
'value' => old('username'),
]) ?>
<?= form_label(lang('Install.form.password'), 'password') ?>
<?= form_input([
'id' => 'password',
'name' => 'password',
'class' => 'form-input mb-4',
'type' => 'password',
'required' => 'required',
'autocomplete' => 'new-password',
]) ?>
<?= button(
icon('check', 'mr-2') . lang('Install.form.submit'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('install/_layout') ?>
<?= $this->section('content') ?>
<?= form_open(route_to('database-config'), [
'class' => 'flex flex-col max-w-sm w-full',
'autocomplete' => 'off',
]) ?>
<?= csrf_field() ?>
<h1 class="mb-2 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700 font-body">2/4</span><?= lang(
'Install.form.database_config',
) ?></h1>
<p class="mb-4 text-sm text-gray-600"><?= lang(
'Install.form.database_config_hint',
) ?></p>
<?= form_label(lang('Install.form.db_hostname'), 'db_hostname') ?>
<?= form_input([
'id' => 'db_hostname',
'name' => 'db_hostname',
'class' => 'form-input mb-4',
'value' => old('db_hostname', config('Database')->default['hostname']),
'required' => 'required',
]) ?>
<?= form_label(lang('Install.form.db_name'), 'db_name') ?>
<?= form_input([
'id' => 'db_name',
'name' => 'db_name',
'class' => 'form-input mb-4',
'value' => old('db_name', config('Database')->default['database']),
'required' => 'required',
]) ?>
<?= form_label(lang('Install.form.db_username'), 'db_username') ?>
<?= form_input([
'id' => 'db_username',
'name' => 'db_username',
'class' => 'form-input mb-4',
'value' => old('db_username', config('Database')->default['username']),
'required' => 'required',
'autocomplete' => 'off',
]) ?>
<?= form_label(lang('Install.form.db_password'), 'db_password') ?>
<?= form_input([
'id' => 'db_password',
'name' => 'db_password',
'class' => 'form-input mb-4',
'value' => old('db_password', config('Database')->default['password']),
'type' => 'password',
'required' => 'required',
'autocomplete' => 'off',
]) ?>
<?= form_label(
lang('Install.form.db_prefix'),
'db_prefix',
[],
lang('Install.form.db_prefix_hint'),
) ?>
<?= form_input([
'id' => 'db_prefix',
'name' => 'db_prefix',
'class' => 'form-input mb-6',
'value' => old('db_prefix', config('Database')->default['DBPrefix']),
]) ?>
<?= button(
lang('Install.form.next') . icon('arrow-right', 'ml-2'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= $this->extend('install/_layout') ?>
<?= $this->section('content') ?>
<form action="<?= '/' .
config('App')->installGateway .
'/instance-config' ?>" class="flex flex-col w-full max-w-sm" method="post" accept-charset="utf-8">
<?= csrf_field() ?>
<h1 class="mb-4 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700 font-body">1/4</span><?= lang(
'Install.form.instance_config',
) ?></h1>
<?= form_label(lang('Install.form.hostname'), 'hostname') ?>
<?= form_input([
'id' => 'hostname',
'name' => 'hostname',
'class' => 'form-input mb-4',
'value' => old(
'hostname',
host_url() === null ? config('App')->baseURL : host_url(),
),
'required' => 'required',
]) ?>
<?= form_label(
lang('Install.form.media_base_url'),
'media_base_url',
[],
lang('Install.form.media_base_url_hint'),
true,
) ?>
<?= form_input([
'id' => 'media_base_url',
'name' => 'media_base_url',
'class' => 'form-input mb-4',
'value' => old('media_base_url', ''),
]) ?>
<?= form_label(
lang('Install.form.admin_gateway'),
'admin_gateway',
[],
lang('Install.form.admin_gateway_hint'),
) ?>
<?= form_input([
'id' => 'admin_gateway',
'name' => 'admin_gateway',
'class' => 'form-input mb-4',
'value' => old('admin_gateway', config('App')->adminGateway),
'required' => 'required',
]) ?>
<?= form_label(
lang('Install.form.auth_gateway'),
'auth_gateway',
[],
lang('Install.form.auth_gateway_hint'),
) ?>
<?= form_input([
'id' => 'auth_gateway',
'name' => 'auth_gateway',
'class' => 'form-input mb-6',
'value' => old('auth_gateway', config('App')->authGateway),
'required' => 'required',
]) ?>
<?= button(
lang('Install.form.next') . icon('arrow-right', 'ml-2'),
'',
['variant' => 'primary'],
['type' => 'submit', 'class' => 'self-end'],
) ?>
<?= form_close() ?>
<?= $this->endSection() ?>
<?= helper('page') ?>
<!DOCTYPE html>
<html lang="<?= service('request')->getLocale() ?>">
<head>
<meta charset="UTF-8"/>
<title><?= $page->title ?></title>
<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">
<header class="py-8 text-white border-b bg-pine-900">
<div class="container flex flex-col px-2 py-4 mx-auto">
<a href="<?= route_to('home') ?>"
class="inline-flex items-center mb-2"><?= icon(
'arrow-left',
'mr-2',
) . lang('Page.back_to_home') ?></a>
<h1 class="text-3xl font-semibold"><?= $page->title ?></h1>
</div>
</header>
<main class="container flex-1 px-4 py-10 mx-auto">
<div class="prose">
<?= $page->content_html ?>
</div>
</main>
<footer class="container flex justify-between px-2 py-4 mx-auto text-sm text-right border-t">
<?= render_page_links() ?>
<small><?= lang('Common.powered_by', [
'castopod' =>
'<a class="underline hover:no-underline" href="https://castopod.org/" target="_blank" rel="noreferrer noopener">Castopod</a>',
]) ?></small>
</footer>
</body>
<?php
<?php declare(strict_types=1);
use CodeIgniter\Pager\PagerRenderer;
/**
* @var PagerRenderer $pager
*/
/** @var PagerRenderer $pager */
$pager->setSurroundCount(2);
?>
......@@ -13,15 +11,15 @@ $pager->setSurroundCount(2);
<?php if ($pager->hasPreviousPage()): ?>
<li>
<a href="<?= $pager->getFirst() ?>" aria-label="<?= lang(
'Pager.first',
) ?>" class="block px-3 py-2 text-gray-700 hover:bg-gray-200 hover:text-black">
'Pager.first',
) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight">
<span aria-hidden="true"><?= lang('Pager.first') ?></span>
</a>
</li>
<li>
<a href="<?= $pager->getPreviousPage() ?>" aria-label="<?= lang(
'Pager.previous',
) ?>" class="block px-3 py-2 text-gray-700 hover:bg-gray-200 hover:text-black">
'Pager.previous',
) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight">
<span aria-hidden="true"><?= lang(
'Pager.previous',
) ?></span>
......@@ -32,13 +30,11 @@ $pager->setSurroundCount(2);
<?php foreach ($pager->links() as $link): ?>
<li>
<?php if ($link['active']): ?>
<span class="block px-4 py-2 font-semibold text-white rounded-full bg-pine-600">
<span class="block px-4 py-2 font-semibold rounded-full text-accent-contrast bg-accent-base">
<?= $link['title'] ?>
</span>
<?php else: ?>
<a href="<?= $link[
'uri'
] ?>" class="block px-4 py-2 text-gray-700 rounded-full hover:bg-gray-200 hover:text-black">
<a href="<?= $link['uri'] ?>" class="block px-4 py-2 rounded-full text-skin-muted hover:bg-highlight">
<?= $link['title'] ?>
</a>
<?php endif; ?>
......@@ -48,15 +44,15 @@ $pager->setSurroundCount(2);
<?php if ($pager->hasNextPage()): ?>
<li>
<a href="<?= $pager->getNextPage() ?>" aria-label="<?= lang(
'Pager.next',
) ?>" class="block px-3 py-2 text-gray-700 hover:bg-gray-200 hover:text-black">
'Pager.next',
) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight">
<span aria-hidden="true"><?= lang('Pager.next') ?></span>
</a>
</li>
<li>
<a href="<?= $pager->getLast() ?>" aria-label="<?= lang(
'Pager.last',
) ?>" class="block px-3 py-2 text-gray-700 hover:bg-gray-200 hover:text-black">
'Pager.last',
) ?>" class="block px-3 py-2 text-skin-muted hover:bg-highlight">
<span aria-hidden="true"><?= lang('Pager.last') ?></span>
</a>
</li>
......
<?= helper('page') ?>
<!DOCTYPE html>
<html lang="<?= service('request')->getLocale() ?>">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
<?= $this->renderSection('meta-tags') ?>
<?php if ($podcast->payment_pointer): ?>
<meta name="monetization" content="<?= $podcast->payment_pointer ?>" />
<?php endif; ?>
<link rel="stylesheet" href="/assets/index.css"/>
<script src="/assets/podcast.js" type="module"></script>
</head>
<body class="flex w-full min-h-screen pb-20 overflow-x-hidden lg:mx-auto lg:container bg-pine-50 sm:pb-0">
<?= $this->include('podcast/_partials/header') ?>
<main class="flex-shrink-0 w-full min-w-0 sm:w-auto sm:flex-1 sm:flex-shrink">
<?= $this->renderSection('content') ?>
</main>
<?= $this->include('podcast/_partials/sidebar') ?>
<nav class="fixed bottom-0 left-0 z-50 flex items-center w-full px-4 py-4 sm:hidden">
<div class="flex items-center w-full p-2 rounded-full shadow-2xl bg-pine-900">
<button
data-toggle="main-header"
data-toggle-class="sticky -translate-x-full"
class="flex-shrink-0 mr-3 overflow-hidden rounded-full focus:ring-2 focus:outline-none focus:ring-pine-50">
<img src="<?= $podcast->image
->thumbnail_url ?>" alt="<?= $podcast->title ?>" class="h-14"/>
</button>
<p class="flex flex-col flex-1 min-w-0 mr-2 text-white">
<span class="text-sm font-semibold truncate"><?= $podcast->title ?></span>
<span class="text-xs">@<?= $podcast->name ?></span>
</p>
<?= anchor_popup(
route_to('follow', $podcast->name),
icon(
'social/castopod',
'mr-2 text-xl text-pink-200 group-hover:text-pink-50',
) . lang('Podcast.follow'),
[
'width' => 420,
'height' => 620,
'class' =>
'group inline-flex items-center px-4 py-2 text-xs tracking-wider font-semibold text-white uppercase rounded-full shadow focus:outline-none focus:ring bg-rose-600',
],
) ?>
<button
data-toggle="main-sidebar"
data-toggle-class="translate-x-full"
data-toggle-body-class="-ml-64"
class="p-4 text-xl rounded-full focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
'menu',
) ?><span class="sr-only"><?= lang(
'Podcast.toggle_podcast_sidebar',
) ?></span></button>
</div>
</nav>
<button
data-toggle="main-sidebar"
data-toggle-class="translate-x-full"
data-toggle-body-class="-ml-64"
class="fixed z-40 hidden p-4 text-xl rounded-full shadow-2xl sm:block lg:hidden bottom-4 left-4 bg-pine-900 focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
'menu',
) ?><span class="sr-only"><?= lang(
'Podcast.toggle_podcast_sidebar',
) ?></span></button>
<!-- Funding links modal -->
<div id="funding-links" class="fixed top-0 left-0 z-50 flex items-center justify-center hidden w-screen h-screen">
<div
class="absolute w-full h-full bg-pine-900 bg-opacity-90"
role="button"
data-toggle="funding-links"
data-toggle-class="hidden"
aria-label="<?= lang('Common.close') ?>"></div>
<div class="z-10 w-full max-w-xl bg-white rounded-lg shadow-2xl">
<div class="flex justify-between px-4 py-2 border-b">
<h3 class="self-center text-lg"><?= lang(
'Podcast.funding_links',
['podcastTitle' => $podcast->title],
) ?></h3>
<button
data-toggle="funding-links"
data-toggle-class="hidden"
aria-label="<?= lang('Common.close') ?>"
class="self-start p-1 text-2xl"><?= icon('close') ?></button>
</div>
<div class="flex flex-col items-start p-4 space-y-4">
<?php foreach (
$podcast->fundingPlatforms
as $fundingPlatform
): ?>
<?php if ($fundingPlatform->is_visible): ?>
<a
href="<?= $fundingPlatform->link_url ?>"
title="<?= $fundingPlatform->link_content ?>"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center font-semibold text-pine-900">
<?= icon(
$fundingPlatform->type .
'/' .
$fundingPlatform->slug,
'mr-2',
) . $fundingPlatform->link_url ?>
</a>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
</div>
</body>
<?= helper('page') ?>
<!DOCTYPE html>
<html lang="<?= service('request')->getLocale() ?>">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
<?= $this->renderSection('meta-tags') ?>
<?php if ($podcast->payment_pointer): ?>
<meta name="monetization" content="<?= $podcast->payment_pointer ?>" />
<?php endif; ?>
<link rel="stylesheet" href="/assets/index.css" />
<script src="/assets/podcast.js" type="module"></script>
</head>
<body class="flex w-full min-h-screen pt-12 pb-20 overflow-x-hidden bg-pine-50 lg:mx-auto lg:container sm:pb-0">
<div class="fixed top-0 left-0 z-50 flex items-center justify-between w-full h-12 px-4 text-white shadow bg-pine-900">
<?= anchor(
route_to('admin'),
'castopod' . svg('castopod-logo', 'h-5 ml-1'),
[
'class' =>
'text-2xl inline-flex items-baseline font-bold font-display',
],
) ?>
<?php if (user()->podcasts !== []): ?>
<button type="button" class="inline-flex items-center px-6 py-2 mt-auto font-semibold outline-none focus:ring" id="interact-as-dropdown" data-dropdown="button" data-dropdown-target="interact-as-dropdown-menu" aria-haspopup="true" aria-expanded="false">
<img src="<?= interact_as_actor()
->avatar_image_url ?>" class="w-8 h-8 mr-2 rounded-full" />
<?= '@' . interact_as_actor()->username ?>
<?= icon('caret-down', 'ml-auto') ?>
</button>
<nav id="interact-as-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="bottom-end">
<span class="px-4 text-xs tracking-wider text-gray-700 uppercase"><?= lang(
'Admin.choose_interact',
) ?></span>
<form action="<?= route_to(
'interact-as-actor',
) ?>" method="POST" class="flex flex-col">
<?= csrf_field() ?>
<?php foreach (user()->podcasts as $userPodcast): ?>
<button class="inline-flex items-center w-full px-4 py-1 hover:bg-gray-100" id="<?= "interact-as-actor-{$userPodcast->id}" ?>" name="actor_id" value="<?= $userPodcast->actor_id ?>">
<span class="inline-flex items-center flex-1">
<img src="<?= $userPodcast->image
->thumbnail_url ?>" class="w-8 h-8 mr-2 rounded-full" /><?= $userPodcast->title ?>
<?php if (
interact_as_actor()->id ===
$userPodcast->actor_id
): ?>
</span>
<?= icon(
'check',
'ml-4 bg-pine-900 text-white rounded-full',
) ?>
<?php endif; ?>
</button>
<?php endforeach; ?>
</form>
</nav>
<?php endif; ?>
</div>
<?= $this->include('podcast/_partials/header') ?>
<main class="flex-shrink-0 w-full min-w-0 sm:w-auto sm:flex-1 sm:flex-shrink">
<?= $this->renderSection('content') ?>
</main>
<?= $this->include('podcast/_partials/sidebar') ?>
<nav class="fixed bottom-0 left-0 z-50 flex items-center w-full px-4 py-4 sm:hidden">
<div class="flex items-center w-full p-2 rounded-full shadow-2xl bg-pine-900">
<button data-toggle="main-header" data-toggle-class="sticky -translate-x-full" class="flex-shrink-0 mr-3 overflow-hidden rounded-full focus:ring-2 focus:outline-none focus:ring-pine-50">
<img src="<?= $podcast->image
->thumbnail_url ?>" alt="<?= $podcast->title ?>" class="h-14" />
</button>
<p class="flex flex-col flex-1 min-w-0 mr-2 text-white">
<span class="text-sm font-semibold truncate"><?= $podcast->title ?></span>
<span class="text-xs">@<?= $podcast->name ?></span>
</p>
<?= anchor_popup(
route_to('follow', $podcast->name),
icon(
'social/castopod',
'mr-2 text-xl text-pink-200 group-hover:text-pink-50',
) . lang('Podcast.follow'),
[
'width' => 420,
'height' => 620,
'class' =>
'group inline-flex items-center px-4 py-2 text-xs tracking-wider font-semibold text-white uppercase rounded-full shadow focus:outline-none focus:ring bg-rose-600',
],
) ?>
<button data-toggle="main-sidebar" data-toggle-class="translate-x-full" data-toggle-body-class="-ml-64" class="p-4 text-xl rounded-full focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
'menu',
) ?><span class="sr-only"><?= lang(
'Podcast.toggle_podcast_sidebar',
) ?></span></button>
</div>
</nav>
<button data-toggle="main-sidebar" data-toggle-class="translate-x-full" data-toggle-body-class="-ml-64" class="fixed z-40 hidden p-4 text-xl rounded-full shadow-2xl sm:block lg:hidden bottom-4 left-4 bg-pine-900 focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
'menu',
) ?><span class="sr-only"><?= lang(
'Podcast.toggle_podcast_sidebar',
) ?></span></button>
<!-- Funding links modal -->
<div id="funding-links" class="fixed top-0 left-0 z-50 flex items-center justify-center hidden w-screen h-screen">
<div class="absolute w-full h-full bg-pine-900 bg-opacity-90" role="button" data-toggle="funding-links" data-toggle-class="hidden" aria-label="<?= lang(
'Common.close',
) ?>"></div>
<div class="z-10 w-full max-w-xl bg-white rounded-lg shadow-2xl">
<div class="flex justify-between px-4 py-2 border-b">
<h3 class="self-center text-lg"><?= lang(
'Podcast.funding_links',
['podcastTitle' => $podcast->title],
) ?></h3>
<button data-toggle="funding-links" data-toggle-class="hidden" aria-label="<?= lang(
'Common.close',
) ?>" class="self-start p-1 text-2xl">
<?= icon('close') ?>
</button>
</div>
<div class="flex flex-col items-start p-4 space-y-4">
<?php foreach (
$podcast->fundingPlatforms
as $fundingPlatform
): ?>
<?php if ($fundingPlatform->is_visible): ?>
<a href="<?= $fundingPlatform->link_url ?>" title="<?= $fundingPlatform->link_content ?>" target="_blank" rel="noopener noreferrer" class="inline-flex items-center font-semibold text-pine-900">
<?= icon(
$fundingPlatform->type .
'/' .
$fundingPlatform->slug,
'text-2xl text-gray-400 mr-2',
) . $fundingPlatform->link_url ?>
</a>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
</div>
</body>
<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 font-semibold leading-none 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-800">
<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_web_url ?>"
type="<?= $episode->audio_file_mimetype ?>">
Your browser does not support the audio tag.
</audio>
</div>
</div>
<header id="main-header" class="fixed top-0 left-0 flex-col flex-shrink-0 h-screen transform -translate-x-full sm:left-auto sm:-translate-x-0 sm:sticky w-80 sm:w-64 lg:w-80 xl:w-112 sm:flex">
<img src="<?= $podcast->actor
->cover_image_url ?>" alt="" class="object-cover w-full h-48 bg-pine-900"/>
<div class="flex items-center justify-between px-4 py-2 mb-4 lg:px-6 -mt-14 lg:-mt-16 xl:-mt-20">
<img src="<?= $podcast->image
->thumbnail_url ?>" alt="<?= $podcast->title ?>" class="h-24 rounded-full shadow-xl xl:h-36 lg:h-28 ring-4 ring-pine-50" />
<?= anchor_popup(
route_to('follow', $podcast->name),
icon(
'social/castopod',
'mr-2 text-xl text-pink-200 group-hover:text-pink-50',
) . lang('Podcast.follow'),
[
'width' => 420,
'height' => 620,
'class' =>
'group inline-flex items-center px-4 py-2 text-xs tracking-wider font-semibold text-white uppercase rounded-full shadow focus:outline-none focus:ring bg-rose-600',
],
) ?>
</div>
<div class="px-6">
<h1 class="inline-flex items-center text-2xl font-bold leading-none font-display"><?= $podcast->title .
($podcast->parental_advisory === 'explicit'
? '<span class="px-1 ml-2 text-xs font-semibold leading-tight tracking-wider text-gray-600 uppercase border-2 border-gray-500">' .
lang('Common.explicit') .
'</span>'
: '') ?></h1>
<p class="mb-4 font-semibold text-gray-600">@<?= $podcast->name ?></p>
<div class="mb-2"><?= $podcast->description_html ?></div>
<?= location_link($podcast->location, 'text-sm mb-4') ?>
<div class="mb-6 space-x-4">
<span class="px-2 py-1 text-sm text-gray-800 bg-gray-200">
<?= lang(
'Podcast.category_options.' . $podcast->category->code,
) ?>
</span>
<?php foreach ($podcast->other_categories as $other_category): ?>
<span class="px-2 py-1 text-sm text-gray-800 bg-gray-200">
<?= lang(
'Podcast.category_options.' . $other_category->code,
) ?>
</span>
<?php endforeach; ?>
</div>
<?= person_list($podcast->persons, 'mb-6') ?>
<div class="space-x-4">
<a href="#" class="hover:underline"><?= lang('Podcast.followers', [
'numberOfFollowers' => $podcast->actor->followers_count,
]) ?></a>
<a href="<?= route_to(
'podcast-activity',
$podcast->name,
) ?>" class="hover:underline"><?= lang('Podcast.notes', [
'numberOfNotes' => $podcast->actor->notes_count,
]) ?></a>
</div>
</div>
</header>
<article class="relative z-10 w-full bg-white shadow-md rounded-2xl">
<header class="flex px-6 py-4">
<img src="<?= $note->actor
->avatar_image_url ?>" alt="<?= $note->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0">
<a href="<?= $note->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $note
->actor->is_local
? ''
: 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $note->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $note->actor
->username .
($note->actor->is_local
? ''
: '@' . $note->actor->domain) ?></span>
</a>
<a href="<?= route_to('note', $podcast->name, $note->id) ?>"
class="text-xs text-gray-500">
<time
itemprop="published"
datetime="<?= $note->published_at->format(DateTime::ATOM) ?>"
title="<?= $note->published_at ?>"
><?= lang('Common.mediumDate', [$note->published_at]) ?></time>
</a>
</div>
</header>
<div class="px-6 mb-4 note-content"><?= $note->message_html ?></div>
<?php if ($note->episode_id): ?>
<?= view('podcast/_partials/episode_card', [
'episode' => $note->episode,
]) ?>
<?php elseif ($note->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [
'preview_card' => $note->preview_card,
]) ?>
<?php endif; ?>
<?= $this->include('podcast/_partials/note_actions') ?>
</article>
<footer class="flex justify-around px-6 py-3">
<?= anchor(
route_to('note', $podcast->name, $note->id),
icon('chat', 'text-2xl mr-1 text-gray-400') . $note->replies_count,
[
'class' => 'inline-flex items-center hover:underline',
'title' => lang('Note.replies', [
'numberOfReplies' => $note->replies_count,
]),
],
) ?>
<?= anchor_popup(
route_to('note-remote-action', $podcast->name, $note->id, 'reblog'),
icon('repeat', 'text-2xl mr-1 text-gray-400') . $note->reblogs_count,
[
'class' => 'inline-flex items-center hover:underline',
'width' => 420,
'height' => 620,
'title' => lang('Note.reblogs', [
'numberOfReblogs' => $note->reblogs_count,
]),
],
) ?>
<?= anchor_popup(
route_to('note-remote-action', $podcast->name, $note->id, 'favourite'),
icon('heart', 'text-2xl mr-1 text-gray-400') . $note->favourites_count,
[
'class' => 'inline-flex items-center hover:underline',
'width' => 420,
'height' => 620,
'title' => lang('Note.favourites', [
'numberOfFavourites' => $note->favourites_count,
]),
],
) ?>
</footer>
<footer class="px-6 py-3">
<form action="<?= route_to(
'note-attempt-action',
interact_as_actor()->username,
$note->id,
) ?>" method="POST" class="flex justify-around">
<?= csrf_field() ?>
<?= anchor(
route_to('note', $podcast->name, $note->id),
icon('chat', 'text-2xl mr-1 text-gray-400') . $note->replies_count,
[
'class' => 'inline-flex items-center hover:underline',
'title' => lang('Note.replies', [
'numberOfReplies' => $note->replies_count,
]),
],
) ?>
<button type="submit" name="action" value="reblog" class="inline-flex items-center hover:underline" title="<?= lang(
'Note.reblogs',
[
'numberOfReblogs' => $note->reblogs_count,
],
) ?>"><?= icon('repeat', 'text-2xl mr-1 text-gray-400') .
$note->reblogs_count ?></button>
<button type="submit" name="action" value="favourite" class="inline-flex items-center hover:underline" title="<?= lang(
'Note.favourites',
[
'numberOfFavourites' => $note->favourites_count,
],
) ?>"><?= icon('heart', 'text-2xl mr-1 text-gray-400') .
$note->favourites_count ?></button>
<button id="<?= $note->id .
'-more-dropdown' ?>" type="button" class="px-2 py-1 text-2xl text-gray-500 outline-none focus:ring" data-dropdown="button" data-dropdown-target="<?= $note->id .
'-more-dropdown-menu' ?>" aria-label="<?= lang(
'Common.more',
) ?>" aria-haspopup="true" aria-expanded="false"><?= icon('more') ?>
</button>
</form>
<nav id="<?= $note->id .
'-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm bg-white border rounded-lg shadow" aria-labelledby="<?= $note->id .
'-more-dropdown' ?>" data-dropdown="menu" data-dropdown-placement="bottom">
<?= anchor(
route_to('note', $podcast->name, $note->id),
lang('Note.expand'),
[
'class' => 'px-4 py-1 hover:bg-gray-100',
],
) ?>
<form action="<?= route_to(
'note-attempt-block-actor',
interact_as_actor()->username,
$note->id,
) ?>" method="POST">
<?= csrf_field() ?>
<button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang(
'Note.block_actor',
[
'actorUsername' => $note->actor->username,
],
) ?></button>
</form>
<form action="<?= route_to(
'note-attempt-block-domain',
interact_as_actor()->username,
$note->id,
) ?>" method="POST">
<?= csrf_field() ?>
<button class="w-full px-4 py-1 text-left hover:bg-gray-100"><?= lang(
'Note.block_domain',
[
'actorDomain' => $note->actor->domain,
],
) ?></button>
</form>
<?php if ($note->actor->is_local): ?>
<hr class="my-2" />
<form action="<?= route_to(
'note-attempt-delete',
$note->actor->username,
$note->id,
) ?>" method="POST">
<?= csrf_field() ?>
<button class="w-full px-4 py-1 font-semibold text-left text-red-600 hover:bg-gray-100"><?= lang(
'Note.delete',
) ?></button>
</form>
<?php endif; ?>
</nav>
</footer>
<article class="relative z-10 w-full bg-white shadow-md rounded-2xl">
<header class="flex px-6 py-4">
<img src="<?= $note->actor
->avatar_image_url ?>" alt="<?= $note->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col min-w-0">
<a href="<?= $note->actor
->uri ?>" class="flex items-baseline hover:underline" <?= $note
->actor->is_local
? ''
: 'target="_blank" rel="noopener noreferrer"' ?>>
<span class="mr-2 font-semibold truncate"><?= $note->actor
->display_name ?></span>
<span class="text-sm text-gray-500 truncate">@<?= $note->actor
->username .
($note->actor->is_local
? ''
: '@' . $note->actor->domain) ?></span>
</a>
<a href="<?= route_to('note', $podcast->name, $note->id) ?>"
class="text-xs text-gray-500">
<time
itemprop="published"
datetime="<?= $note->published_at->format(DateTime::ATOM) ?>"
title="<?= $note->published_at ?>"
><?= lang('Common.mediumDate', [$note->published_at]) ?></time>
</a>
</div>
</header>
<div class="px-6 mb-4 note-content"><?= $note->message_html ?></div>
<?php if ($note->episode_id): ?>
<?= view('podcast/_partials/episode_card', [
'episode' => $note->episode,
]) ?>
<?php elseif ($note->has_preview_card): ?>
<?= view('podcast/_partials/preview_card', [
'preview_card' => $note->preview_card,
]) ?>
<?php endif; ?>
<?= $this->include('podcast/_partials/note_actions_authenticated') ?>
</article>
<?= $this->include('podcast/_partials/note') ?>
<div class="-mt-2 overflow-hidden border-b border-l border-r note-replies rounded-b-xl">
<div class="px-6 pt-8 pb-4 bg-gray-50">
<?= anchor_popup(
route_to('note-remote-action', $podcast->name, $note->id, 'reply'),
lang('Note.reply_to', ['actorUsername' => $note->actor->username]),
[
'class' =>
'text-center justify-center font-semibold rounded-full shadow relative z-10 px-4 py-2 w-full bg-rose-600 text-white inline-flex items-center hover:bg-rose-700',
'width' => 420,
'height' => 620,
],
) ?>
</div>
<?php if ($note->has_replies): ?>
<?php foreach ($note->replies as $reply): ?>
<?= view('podcast/_partials/reply', ['reply' => $reply]) ?>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?= $this->include('podcast/_partials/note_authenticated') ?>
<div class="-mt-2 overflow-hidden border-b border-l border-r note-replies rounded-b-xl">
<?= form_open(
route_to('note-attempt-action', interact_as_actor()->username, $note->id),
[
'class' => 'bg-gray-50 flex px-6 pt-8 pb-4',
],
) ?>
<img src="<?= interact_as_actor()
->avatar_image_url ?>" alt="<?= interact_as_actor()
->display_name ?>" class="w-12 h-12 mr-4 rounded-full ring-gray-50 ring-2" />
<div class="flex flex-col flex-1">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea mb-4 w-full',
'required' => 'required',
'placeholder' => lang('Note.form.reply_to_placeholder', [
'actorUsername' => $note->actor->username,
]),
],
old('message', '', false),
[
'rows' => 1,
],
) ?>
<?= button(
lang('Note.form.submit_reply'),
'',
['variant' => 'primary', 'size' => 'small'],
[
'type' => 'submit',
'class' => 'self-end',
'name' => 'action',
'value' => 'reply',
],
) ?>
</div>
<?= form_close() ?>
<?php if ($note->has_replies): ?>
<?php foreach ($note->replies as $reply): ?>
<?= view('podcast/_partials/reply_authenticated', [
'reply' => $reply,
]) ?>
<?php endforeach; ?>
<?php endif; ?>
</div>