mirror of
https://code.castopod.org/adaures/castopod.git
synced 2024-09-28 04:31:47 +02:00
feat: simplify podcast page's layout for better ux
This commit is contained in:
parent
c639c4148c
commit
2c0efc6563
@ -80,6 +80,9 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
$routes->get('about', 'PodcastController::about/$1', [
|
||||||
|
'as' => 'podcast-about',
|
||||||
|
]);
|
||||||
$routes->options('episodes', 'ActivityPubController::preflight');
|
$routes->options('episodes', 'ActivityPubController::preflight');
|
||||||
$routes->get('episodes', 'PodcastController::episodes/$1', [
|
$routes->get('episodes', 'PodcastController::episodes/$1', [
|
||||||
'as' => 'podcast-episodes',
|
'as' => 'podcast-episodes',
|
||||||
|
@ -105,6 +105,51 @@ class PodcastController extends BaseController
|
|||||||
return $cachedView;
|
return $cachedView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function about(): string
|
||||||
|
{
|
||||||
|
// Prevent analytics hit when authenticated
|
||||||
|
if (! can_user_interact()) {
|
||||||
|
$this->registerPodcastWebpageHit($this->podcast->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cacheName = implode(
|
||||||
|
'_',
|
||||||
|
array_filter([
|
||||||
|
'page',
|
||||||
|
"podcast#{$this->podcast->id}",
|
||||||
|
'about',
|
||||||
|
service('request')
|
||||||
|
->getLocale(),
|
||||||
|
can_user_interact() ? '_authenticated' : null,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! ($cachedView = cache($cacheName))) {
|
||||||
|
$data = [
|
||||||
|
'podcast' => $this->podcast,
|
||||||
|
];
|
||||||
|
|
||||||
|
// if user is logged in then send to the authenticated activity view
|
||||||
|
if (can_user_interact()) {
|
||||||
|
helper('form');
|
||||||
|
return view('podcast/about_authenticated', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$secondsToNextUnpublishedEpisode = (new EpisodeModel())->getSecondsToNextUnpublishedEpisode(
|
||||||
|
$this->podcast->id,
|
||||||
|
);
|
||||||
|
|
||||||
|
return view('podcast/about', $data, [
|
||||||
|
'cache' => $secondsToNextUnpublishedEpisode
|
||||||
|
? $secondsToNextUnpublishedEpisode
|
||||||
|
: DECADE,
|
||||||
|
'cache_name' => $cacheName,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cachedView;
|
||||||
|
}
|
||||||
|
|
||||||
public function episodes(): string
|
public function episodes(): string
|
||||||
{
|
{
|
||||||
// Prevent analytics hit when authenticated
|
// Prevent analytics hit when authenticated
|
||||||
|
@ -23,10 +23,10 @@ if (! function_exists('render_page_links')) {
|
|||||||
'class' => 'px-2 py-1 underline hover:no-underline',
|
'class' => 'px-2 py-1 underline hover:no-underline',
|
||||||
]);
|
]);
|
||||||
$links .= anchor(route_to('credits'), lang('Person.credits'), [
|
$links .= anchor(route_to('credits'), lang('Person.credits'), [
|
||||||
'class' => 'px-2 py-1 underline hover:no-underline',
|
'class' => 'px-2 py-1 underline hover:no-underline',
|
||||||
]);
|
]);
|
||||||
$links .= anchor(route_to('map'), lang('Page.map'), [
|
$links .= anchor(route_to('map'), lang('Page.map'), [
|
||||||
'class' => 'px-2 underline hover:no-underline',
|
'class' => 'px-2 py-1 underline hover:no-underline',
|
||||||
]);
|
]);
|
||||||
foreach ($pages as $page) {
|
foreach ($pages as $page) {
|
||||||
$links .= anchor($page->link, $page->title, [
|
$links .= anchor($page->link, $page->title, [
|
||||||
|
@ -42,6 +42,7 @@ return [
|
|||||||
}',
|
}',
|
||||||
'activity' => 'Activity',
|
'activity' => 'Activity',
|
||||||
'episodes' => 'Episodes',
|
'episodes' => 'Episodes',
|
||||||
|
'about' => 'About',
|
||||||
'sponsor_title' => 'Enjoying the show?',
|
'sponsor_title' => 'Enjoying the show?',
|
||||||
'sponsor' => 'Sponsor',
|
'sponsor' => 'Sponsor',
|
||||||
'funding_links' => 'Funding links for {podcastTitle}',
|
'funding_links' => 'Funding links for {podcastTitle}',
|
||||||
|
@ -42,6 +42,7 @@ return [
|
|||||||
}',
|
}',
|
||||||
'activity' => 'Activité',
|
'activity' => 'Activité',
|
||||||
'episodes' => 'Épisodes',
|
'episodes' => 'Épisodes',
|
||||||
|
'about' => 'About',
|
||||||
'sponsor_title' => 'Vous aimez le podcast ?',
|
'sponsor_title' => 'Vous aimez le podcast ?',
|
||||||
'sponsor' => 'Soutenez-nous',
|
'sponsor' => 'Soutenez-nous',
|
||||||
'funding_links' => 'Liens de financement pour {podcastTitle}',
|
'funding_links' => 'Liens de financement pour {podcastTitle}',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||||
|
const colors = require("tailwindcss/colors");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: "jit",
|
mode: "jit",
|
||||||
@ -42,6 +43,7 @@ module.exports = {
|
|||||||
800: "#b21a39",
|
800: "#b21a39",
|
||||||
900: "#8e162e",
|
900: "#8e162e",
|
||||||
},
|
},
|
||||||
|
orange: colors.orange,
|
||||||
},
|
},
|
||||||
spacing: {
|
spacing: {
|
||||||
112: "28rem",
|
112: "28rem",
|
||||||
|
46
themes/cp_app/_admin_navbar.php
Normal file
46
themes/cp_app/_admin_navbar.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<div class="sticky top-0 left-0 z-50 flex items-center justify-between w-full h-12 px-4 text-white border-b shadow bg-pine-800 border-pine-900">
|
||||||
|
<?= anchor(
|
||||||
|
route_to('admin'),
|
||||||
|
'castopod' . svg('castopod-logo-base', '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-800 text-white rounded-full',
|
||||||
|
) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</button>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</form>
|
||||||
|
</nav>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
@ -17,7 +17,11 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="flex flex-col min-h-screen mx-auto bg-gray-100">
|
<body class="flex flex-col min-h-screen mx-auto bg-gray-100">
|
||||||
<header class="py-8 text-white border-b bg-pine-900">
|
<?php if (service('authentication')->check()): ?>
|
||||||
|
<?= $this->include('_admin_navbar') ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<header class="py-8 text-white border-b bg-pine-800">
|
||||||
<div class="container flex flex-col px-2 py-4 mx-auto">
|
<div class="container flex flex-col px-2 py-4 mx-auto">
|
||||||
<a href="<?= route_to('home') ?>"
|
<a href="<?= route_to('home') ?>"
|
||||||
class="inline-flex items-center mb-2"><?= icon(
|
class="inline-flex items-center mb-2"><?= icon(
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="flex flex-col min-h-screen mx-auto bg-pine-50">
|
<body class="flex flex-col min-h-screen mx-auto bg-pine-50">
|
||||||
|
<?php if (service('authentication')->check()): ?>
|
||||||
|
<?= $this->include('_admin_navbar') ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<header class="py-8 text-white border-b bg-pine-800">
|
<header class="py-8 text-white border-b bg-pine-800">
|
||||||
<div class="container flex items-center justify-between px-2 py-4 mx-auto">
|
<div class="container flex items-center justify-between px-2 py-4 mx-auto">
|
||||||
<a href="<?= route_to(
|
<a href="<?= route_to(
|
||||||
|
@ -16,7 +16,11 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="flex flex-col h-full min-h-screen mx-auto bg-gray-100">
|
<body class="flex flex-col h-full min-h-screen mx-auto bg-gray-100">
|
||||||
<header class="py-8 text-white border-b bg-pine-900">
|
<?php if (service('authentication')->check()): ?>
|
||||||
|
<?= $this->include('_admin_navbar') ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<header class="py-8 text-white border-b bg-pine-800">
|
||||||
<div class="container flex flex-col px-2 py-4 mx-auto">
|
<div class="container flex flex-col px-2 py-4 mx-auto">
|
||||||
<a href="<?= route_to('home') ?>"
|
<a href="<?= route_to('home') ?>"
|
||||||
class="inline-flex items-center mb-2"><?= icon(
|
class="inline-flex items-center mb-2"><?= icon(
|
@ -13,6 +13,10 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="flex flex-col min-h-screen mx-auto">
|
<body class="flex flex-col min-h-screen mx-auto">
|
||||||
|
<?php if (service('authentication')->check()): ?>
|
||||||
|
<?= $this->include('_admin_navbar') ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<header class="py-8 text-white border-b bg-pine-800">
|
<header class="py-8 text-white border-b bg-pine-800">
|
||||||
<div class="container flex flex-col px-2 py-4 mx-auto">
|
<div class="container flex flex-col px-2 py-4 mx-auto">
|
||||||
<a href="<?= route_to('home') ?>"
|
<a href="<?= route_to('home') ?>"
|
||||||
|
123
themes/cp_app/podcast/_layout copy.php
Normal file
123
themes/cp_app/podcast/_layout copy.php
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?= 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; ?>
|
||||||
|
|
||||||
|
<?= service('vite')
|
||||||
|
->asset('styles/index.css', 'css') ?>
|
||||||
|
<?= service('vite')
|
||||||
|
->asset('js/podcast.ts', 'js') ?>
|
||||||
|
<?= service('vite')
|
||||||
|
->asset('js/audio-player.ts', 'js') ?>
|
||||||
|
</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">
|
||||||
|
<nav class="sticky top-0 left-0 z-50 flex items-center w-full h-12 px-2 py-1 sm:hidden bg-pine-800">
|
||||||
|
<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-10"/>
|
||||||
|
</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->handle ?></span>
|
||||||
|
</p>
|
||||||
|
<?= anchor_popup(
|
||||||
|
route_to('follow', $podcast->handle),
|
||||||
|
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 mr-2 items-center px-3 py-1 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-2 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>
|
||||||
|
</nav>
|
||||||
|
<?= $this->renderSection('content') ?>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?= $this->include('podcast/_partials/sidebar') ?>
|
||||||
|
|
||||||
|
<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-800 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-800 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>
|
@ -22,102 +22,116 @@
|
|||||||
->asset('js/audio-player.ts', 'js') ?>
|
->asset('js/audio-player.ts', 'js') ?>
|
||||||
</head>
|
</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">
|
<body class="grid items-start w-1/2 grid-cols-9 mx-auto bg-pine-50 gap-y-8 gap-x-6">
|
||||||
<?= $this->include('podcast/_partials/header') ?>
|
<header class="sticky z-50 flex flex-col bg-white shadow -top-96 rounded-b-xl col-span-full">
|
||||||
|
<div style="background-image: url('<?= $podcast->actor->cover_image_url ?>'); background-size: auto 320px;" class="w-full bg-fixed bg-top bg-no-repeat bg-cover bg-pine-800 h-80"></div>
|
||||||
|
<div class="flex items-center justify-between py-4 ml-8 -mt-28">
|
||||||
|
<div class="flex items-center gap-x-4">
|
||||||
|
<img src="<?= $podcast->image->thumbnail_url ?>" alt="<?= $podcast->title ?>" loading="lazy" class="rounded-full h-36 ring-4 ring-white" />
|
||||||
|
<div class="flex flex-col -mt-4 text-white">
|
||||||
|
<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>
|
||||||
|
<a href="#" class="hover:underline"><?= lang('Podcast.followers', [
|
||||||
|
'numberOfFollowers' => $podcast->actor->followers_count,
|
||||||
|
]) ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<main class="flex-shrink-0 w-full min-w-0 sm:w-auto sm:flex-1 sm:flex-shrink">
|
<div class="inline-flex items-center mr-4 -mt-4 gap-x-2">
|
||||||
<nav class="sticky top-0 left-0 z-50 flex items-center w-full h-12 px-2 py-1 sm:hidden bg-pine-800">
|
<?php if (in_array(true, array_column($podcast->fundingPlatforms, 'is_visible'), true)): ?>
|
||||||
<button
|
<IconButton glyph="heart" data-toggle="funding-links" data-toggle-class="hidden"><?= lang('Podcast.sponsor') . lang('Podcast.sponsor_title') ?></IconButton>
|
||||||
data-toggle="main-header"
|
<?php endif; ?>
|
||||||
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-10"/>
|
|
||||||
</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->handle ?></span>
|
|
||||||
</p>
|
|
||||||
<?= anchor_popup(
|
<?= anchor_popup(
|
||||||
route_to('follow', $podcast->handle),
|
route_to('follow', $podcast->handle),
|
||||||
icon(
|
icon(
|
||||||
'social/castopod',
|
'social/castopod',
|
||||||
'mr-2 text-xl text-pink-200 group-hover:text-pink-50',
|
'mr-2 text-xl text-pink-200 group-hover:text-pink-50',
|
||||||
) . lang('Podcast.follow'),
|
) . lang('Podcast.follow'),
|
||||||
[
|
[
|
||||||
'width' => 420,
|
'width' => 420,
|
||||||
'height' => 620,
|
'height' => 620,
|
||||||
'class' =>
|
'class' =>
|
||||||
'group inline-flex mr-2 items-center px-3 py-1 text-xs tracking-wider font-semibold text-white uppercase rounded-full shadow focus:outline-none focus:ring bg-rose-600',
|
'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
|
</div>
|
||||||
data-toggle="main-sidebar"
|
</div>
|
||||||
data-toggle-class="translate-x-full"
|
<nav class="flex gap-4 px-8">
|
||||||
data-toggle-body-class="-ml-64"
|
<a href="<?= route_to('podcast-activity', $podcast->handle) ?>" class="px-4 py-1 font-semibold uppercase border-b-4 text-pine-500 border-pine-500"><?= lang('Podcast.activity') ?></a>
|
||||||
class="p-2 text-xl rounded-full focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
|
<a href="<?= route_to('podcast-episodes', $podcast->handle) ?>" class="px-4 py-1 font-semibold text-gray-500 uppercase hover:text-black"><?= lang('Podcast.episodes') ?></a>
|
||||||
'menu',
|
<a href="<?= route_to('podcast-about', $podcast->handle) ?>" class="px-4 py-1 font-semibold text-gray-500 uppercase hover:text-black"><?= lang('Podcast.about') ?></a>
|
||||||
) ?><span class="sr-only"><?= lang('Podcast.toggle_podcast_sidebar') ?></span></button>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="col-span-6">
|
||||||
<?= $this->renderSection('content') ?>
|
<?= $this->renderSection('content') ?>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?= $this->include('podcast/_partials/sidebar') ?>
|
<aside class="sticky col-span-3 top-12">
|
||||||
|
<?php if (
|
||||||
<button
|
in_array(true, array_column($podcast->socialPlatforms, 'is_visible'), true)
|
||||||
data-toggle="main-sidebar"
|
): ?>
|
||||||
data-toggle-class="translate-x-full"
|
<h2 class="font-semibold"> <?= lang('Podcast.find_on', [
|
||||||
data-toggle-body-class="-ml-64"
|
'podcastTitle' => $podcast->title,
|
||||||
class="fixed z-40 hidden p-4 text-xl rounded-full shadow-2xl sm:block lg:hidden bottom-4 left-4 bg-pine-800 focus:outline-none focus:ring-2 focus:ring-pine-600 text-pine-200 hover:text-pine-50"><?= icon(
|
]) ?></h2>
|
||||||
'menu',
|
<div class="grid items-center justify-center grid-cols-6 gap-3 mt-2">
|
||||||
) ?><span class="sr-only"><?= lang(
|
<?php foreach ($podcast->socialPlatforms as $socialPlatform): ?>
|
||||||
'Podcast.toggle_podcast_sidebar',
|
<?php if ($socialPlatform->is_visible): ?>
|
||||||
) ?></span></button>
|
<?= anchor(
|
||||||
|
$socialPlatform->link_url,
|
||||||
<!-- Funding links modal -->
|
icon("{$socialPlatform->type}/{$socialPlatform->slug}"),
|
||||||
<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-800 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,
|
'class' => 'text-2xl text-gray-500 hover:text-gray-700 w-8 h-8 items-center inline-flex justify-center',
|
||||||
|
'target' => '_blank',
|
||||||
|
'rel' => 'noopener noreferrer',
|
||||||
|
'data-toggle' => 'tooltip',
|
||||||
|
'data-placement' => 'bottom',
|
||||||
|
'title' => $socialPlatform->label,
|
||||||
],
|
],
|
||||||
) ?></h3>
|
) ?>
|
||||||
<button
|
<?php endif; ?>
|
||||||
data-toggle="funding-links"
|
<?php endforeach; ?>
|
||||||
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>
|
||||||
</div>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<h2 class="mt-6 font-semibold"><?= lang('Podcast.listen_on') ?></h2>
|
||||||
|
<div class="grid items-center justify-center grid-cols-6 gap-3 mt-2">
|
||||||
|
<?= anchor(route_to('podcast_feed', $podcast->handle), icon('rss'), [
|
||||||
|
'class' =>
|
||||||
|
'bg-orange-500 text-xl text-white hover:bg-orange-700 w-8 h-8 inline-flex items-center justify-center rounded-lg',
|
||||||
|
'target' => '_blank',
|
||||||
|
'rel' => 'noopener noreferrer',
|
||||||
|
'data-toggle' => 'tooltip',
|
||||||
|
'data-placement' => 'bottom',
|
||||||
|
'title' => lang('Podcast.feed'),
|
||||||
|
]) ?>
|
||||||
|
<?php foreach ($podcast->podcastingPlatforms as $podcastingPlatform): ?>
|
||||||
|
<?php if ($podcastingPlatform->is_visible): ?>
|
||||||
|
<?= anchor(
|
||||||
|
$podcastingPlatform->link_url,
|
||||||
|
icon(
|
||||||
|
"{$podcastingPlatform->type}/{$podcastingPlatform->slug}",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
'class' => 'text-2xl text-gray-500 hover:text-gray-700 w-8 h-8 items-center inline-flex justify-center',
|
||||||
|
'target' => '_blank',
|
||||||
|
'rel' => 'noopener noreferrer',
|
||||||
|
'data-toggle' => 'tooltip',
|
||||||
|
'data-placement' => 'bottom',
|
||||||
|
'title' => $podcastingPlatform->label,
|
||||||
|
],
|
||||||
|
) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<footer class="flex flex-col items-center py-2 mt-8 text-xs text-center text-gray-600 border-t">
|
||||||
|
<?= render_page_links('inline-flex mb-2 flex-wrap gap-y-1') ?>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<p><?= $podcast->copyright ?></p>
|
||||||
|
<p><?= lang('Common.powered_by', [
|
||||||
|
'castopod' =>
|
||||||
|
'<a class="inline-flex font-semibold hover:underline" href="https://castopod.org" target="_blank" rel="noreferrer noopener">Castopod' . icon('social/castopod', 'ml-1 text-lg') . '</a>',
|
||||||
|
]) ?></p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</aside>
|
||||||
</body>
|
</body>
|
||||||
|
@ -22,53 +22,10 @@
|
|||||||
->asset('js/audio-player.ts', 'js') ?>
|
->asset('js/audio-player.ts', 'js') ?>
|
||||||
</head>
|
</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">
|
<body class="w-full min-h-screen pb-20 overflow-x-hidden bg-pine-50 lg:mx-auto 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-800">
|
<?= $this->include('_admin_navbar') ?>
|
||||||
<?= anchor(
|
<div class="flex">
|
||||||
route_to('admin'),
|
|
||||||
'castopod' . svg('castopod-logo-base', '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-800 text-white rounded-full',
|
|
||||||
) ?>
|
|
||||||
<?php endif; ?>
|
|
||||||
</button>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</form>
|
|
||||||
</nav>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
<?= $this->include('podcast/_partials/header') ?>
|
<?= $this->include('podcast/_partials/header') ?>
|
||||||
|
|
||||||
<main class="flex-shrink-0 w-full min-w-0 sm:w-auto sm:flex-1 sm:flex-shrink">
|
<main class="flex-shrink-0 w-full min-w-0 sm:w-auto sm:flex-1 sm:flex-shrink">
|
||||||
@ -154,4 +111,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
35
themes/cp_app/podcast/about.php
Normal file
35
themes/cp_app/podcast/about.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?= $this->extend('podcast/_layout') ?>
|
||||||
|
|
||||||
|
<?= $this->section('meta-tags') ?>
|
||||||
|
<!-- TODO: -->
|
||||||
|
|
||||||
|
<link type="application/rss+xml" rel="alternate" title="<?= $podcast->title ?>" href="<?= $podcast->feed_url ?>" />
|
||||||
|
|
||||||
|
<title><?= $podcast->title ?></title>
|
||||||
|
<meta name="description" content="<?= htmlspecialchars(
|
||||||
|
$podcast->description,
|
||||||
|
) ?>" />
|
||||||
|
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||||
|
<link rel="canonical" href="<?= current_url() ?>" />
|
||||||
|
<meta property="og:title" content="<?= $podcast->title ?>" />
|
||||||
|
<meta property="og:description" content="<?= $podcast->description ?>" />
|
||||||
|
<meta property="og:locale" content="<?= $podcast->language_code ?>" />
|
||||||
|
<meta property="og:site_name" content="<?= $podcast->title ?>" />
|
||||||
|
<meta property="og:url" content="<?= current_url() ?>" />
|
||||||
|
<meta property="og:image" content="<?= $podcast->image->large_url ?>" />
|
||||||
|
<meta property="og:image:width" content="<?= config('Images')
|
||||||
|
->largeSize ?>" />
|
||||||
|
<meta property="og:image:height" content="<?= config('Images')
|
||||||
|
->largeSize ?>" />
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
|
||||||
|
<?= service('vite')
|
||||||
|
->asset('styles/index.css', 'css') ?>
|
||||||
|
<?= $this->endSection() ?>
|
||||||
|
|
||||||
|
<?= $this->section('content') ?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<?= $this->endSection()
|
||||||
|
?>
|
@ -27,21 +27,7 @@
|
|||||||
|
|
||||||
<?= $this->section('content') ?>
|
<?= $this->section('content') ?>
|
||||||
|
|
||||||
<nav class="sticky z-20 flex justify-center pt-2 text-lg sm:top-0 top-12 bg-pine-50">
|
<section class="max-w-2xl mx-auto space-y-8">
|
||||||
<a href="<?= route_to(
|
|
||||||
'podcast-activity',
|
|
||||||
$podcast->handle,
|
|
||||||
) ?>" class="px-4 py-1 mr-8 font-semibold border-b-4 text-pine-800 border-pine-500"><?= lang(
|
|
||||||
'Podcast.activity',
|
|
||||||
) ?></a>
|
|
||||||
<a href="<?= route_to(
|
|
||||||
'podcast-episodes',
|
|
||||||
$podcast->handle,
|
|
||||||
) ?>" class="px-4 py-1 rounded-full hover:bg-pine-100"><?= lang(
|
|
||||||
'Podcast.episodes',
|
|
||||||
) ?></a>
|
|
||||||
</nav>
|
|
||||||
<section class="max-w-2xl px-6 py-8 mx-auto space-y-8">
|
|
||||||
<?php foreach ($posts as $post): ?>
|
<?php foreach ($posts as $post): ?>
|
||||||
<?php if ($post->reblog_of_id !== null): ?>
|
<?php if ($post->reblog_of_id !== null): ?>
|
||||||
<?= view('podcast/_partials/reblog', [
|
<?= view('podcast/_partials/reblog', [
|
||||||
|
@ -26,63 +26,50 @@
|
|||||||
<?= $this->endSection() ?>
|
<?= $this->endSection() ?>
|
||||||
|
|
||||||
<?= $this->section('content') ?>
|
<?= $this->section('content') ?>
|
||||||
<nav class="sticky z-20 flex items-center justify-center pt-2 text-lg top-12 sm:top-0 bg-pine-50">
|
|
||||||
<a href="<?= route_to(
|
|
||||||
'podcast-activity',
|
|
||||||
$podcast->handle,
|
|
||||||
) ?>" class="px-4 py-1 mr-8 rounded-full hover:bg-pine-100"><?= lang(
|
|
||||||
'Podcast.activity',
|
|
||||||
) ?></a>
|
|
||||||
<a href="<?= route_to(
|
|
||||||
'podcast-episodes',
|
|
||||||
$podcast->handle,
|
|
||||||
) ?>" class="px-4 py-1 font-semibold border-b-4 text-pine-800 border-pine-500"><?= lang(
|
|
||||||
'Podcast.episodes',
|
|
||||||
) ?></a>
|
|
||||||
<?php if ($activeQuery): ?>
|
|
||||||
<button id="episode-lists-dropdown" type="button" class="inline-flex items-center px-2 py-1 text-sm font-semibold outline-none focus:ring" data-dropdown="button" data-dropdown-target="episode-lists-dropdown-menu" aria-label="<?= lang(
|
|
||||||
'Common.more',
|
|
||||||
) ?>" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<?= $activeQuery['label'] .
|
|
||||||
' (' .
|
|
||||||
$activeQuery['number_of_episodes'] .
|
|
||||||
')' .
|
|
||||||
icon('caret-down', 'ml-2 text-xl') ?>
|
|
||||||
</button>
|
|
||||||
<nav id="episode-lists-dropdown-menu" class="flex flex-col py-2 text-black bg-white border rounded shadow" aria-labelledby="episode-lists-dropdown" data-dropdown="menu" data-dropdown-placement="bottom-end">
|
|
||||||
<?php foreach ($episodesNav as $link): ?>
|
|
||||||
<?= anchor(
|
|
||||||
$link['route'],
|
|
||||||
$link['label'] . ' (' . $link['number_of_episodes'] . ')',
|
|
||||||
[
|
|
||||||
'class' =>
|
|
||||||
'px-2 py-1 whitespace-nowrap ' .
|
|
||||||
($link['is_active']
|
|
||||||
? 'font-semibold'
|
|
||||||
: 'text-gray-600 hover:text-gray-900'),
|
|
||||||
],
|
|
||||||
) ?>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</nav>
|
|
||||||
<?php endif; ?>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<section class="flex flex-col max-w-2xl px-6 py-8 mx-auto">
|
|
||||||
|
|
||||||
|
<section class="flex flex-col max-w-2xl">
|
||||||
<?php if ($episodes): ?>
|
<?php if ($episodes): ?>
|
||||||
<h1 class="mb-4 text-xl font-semibold">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<?php if ($activeQuery['type'] === 'year'): ?>
|
<h1 class="text-xl font-semibold">
|
||||||
<?= lang('Podcast.list_of_episodes_year', [
|
<?php if ($activeQuery['type'] === 'year'): ?>
|
||||||
'year' => $activeQuery['value'],
|
<?= lang('Podcast.list_of_episodes_year', [
|
||||||
'episodeCount' => count($episodes),
|
'year' => $activeQuery['value'],
|
||||||
]) ?>
|
'episodeCount' => count($episodes),
|
||||||
<?php elseif ($activeQuery['type'] === 'season'): ?>
|
]) ?>
|
||||||
<?= lang('Podcast.list_of_episodes_season', [
|
<?php elseif ($activeQuery['type'] === 'season'): ?>
|
||||||
'seasonNumber' => $activeQuery['value'],
|
<?= lang('Podcast.list_of_episodes_season', [
|
||||||
'episodeCount' => count($episodes),
|
'seasonNumber' => $activeQuery['value'],
|
||||||
]) ?>
|
'episodeCount' => count($episodes),
|
||||||
|
]) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</h1>
|
||||||
|
<?php if ($activeQuery): ?>
|
||||||
|
<button id="episode-lists-dropdown" type="button" class="inline-flex items-center px-2 py-1 text-sm font-semibold outline-none focus:ring" data-dropdown="button" data-dropdown-target="episode-lists-dropdown-menu" aria-label="<?= lang(
|
||||||
|
'Common.more',
|
||||||
|
) ?>" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<?= $activeQuery['label'] .
|
||||||
|
' (' .
|
||||||
|
$activeQuery['number_of_episodes'] .
|
||||||
|
')' .
|
||||||
|
icon('caret-down', 'ml-2 text-xl') ?>
|
||||||
|
</button>
|
||||||
|
<nav id="episode-lists-dropdown-menu" class="flex flex-col py-2 text-black bg-white border rounded shadow" aria-labelledby="episode-lists-dropdown" data-dropdown="menu" data-dropdown-placement="bottom-end">
|
||||||
|
<?php foreach ($episodesNav as $link): ?>
|
||||||
|
<?= anchor(
|
||||||
|
$link['route'],
|
||||||
|
$link['label'] . ' (' . $link['number_of_episodes'] . ')',
|
||||||
|
[
|
||||||
|
'class' =>
|
||||||
|
'px-2 py-1 whitespace-nowrap ' .
|
||||||
|
($link['is_active']
|
||||||
|
? 'font-semibold'
|
||||||
|
: 'text-gray-600 hover:text-gray-900'),
|
||||||
|
],
|
||||||
|
) ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</nav>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</h1>
|
</div>
|
||||||
<?php foreach ($episodes as $episode): ?>
|
<?php foreach ($episodes as $episode): ?>
|
||||||
<?= view('podcast/_partials/episode_card', [
|
<?= view('podcast/_partials/episode_card', [
|
||||||
'episode' => $episode,
|
'episode' => $episode,
|
||||||
|
Loading…
Reference in New Issue
Block a user