feat(ui): create ViewComponents library to enable building class and view files components
- replace some helper components and forms with class components in the ui - create viewcomponents service and load the component function to be used in views
This commit is contained in:
parent
fcecbe1c68
commit
94872f2338
|
@ -46,6 +46,7 @@ class Autoload extends AutoloadConfig
|
|||
'Config' => APPPATH . 'Config',
|
||||
'ActivityPub' => APPPATH . 'Libraries/ActivityPub',
|
||||
'Analytics' => APPPATH . 'Libraries/Analytics',
|
||||
'ViewComponents' => APPPATH . 'Libraries/ViewComponents',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -84,5 +85,5 @@ class Autoload extends AutoloadConfig
|
|||
* ```
|
||||
* @var array<int, string>
|
||||
*/
|
||||
public $files = [];
|
||||
public $files = [APPPATH . 'Libraries/ViewComponents/Helpers/view_components_helper.php'];
|
||||
}
|
||||
|
|
|
@ -110,7 +110,9 @@ if (! function_exists('button')) {
|
|||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('icon_button')) {
|
||||
/**
|
||||
* Icon Button component
|
||||
|
@ -145,6 +147,7 @@ if (! function_exists('icon_button')) {
|
|||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('hint_tooltip')) {
|
||||
/**
|
||||
* Hint component
|
||||
|
@ -167,7 +170,9 @@ if (! function_exists('hint_tooltip')) {
|
|||
return $tooltip . '">' . icon('question') . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('data_table')) {
|
||||
/**
|
||||
* Data table component
|
||||
|
@ -223,7 +228,9 @@ if (! function_exists('data_table')) {
|
|||
'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('publication_pill')) {
|
||||
/**
|
||||
* Publication pill component
|
||||
|
@ -250,7 +257,9 @@ if (! function_exists('publication_pill')) {
|
|||
'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('publication_button')) {
|
||||
/**
|
||||
* Publication button component
|
||||
|
@ -508,27 +517,5 @@ if (! function_exists('relative_time')) {
|
|||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
if (! function_exists('xml_editor')) {
|
||||
/**
|
||||
* XML Editor field
|
||||
*
|
||||
* @param array<string, mixed> $customData
|
||||
* @param array<string, mixed> $extra
|
||||
*/
|
||||
function xml_editor(array $customData = [], string $value = '', array $extra = []): string
|
||||
{
|
||||
$defaultData = [
|
||||
'slot' => 'textarea',
|
||||
'rows' => 5,
|
||||
];
|
||||
$data = array_merge($defaultData, $customData);
|
||||
|
||||
$textarea = form_textarea($data, $value, $extra);
|
||||
|
||||
return <<<CODE_SAMPLE
|
||||
<xml-editor>{$textarea}</time-ago>
|
||||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -141,38 +141,12 @@ if (! function_exists('form_label')) {
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('form_multiselect')) {
|
||||
/**
|
||||
* Multi-select menu
|
||||
*
|
||||
* @param array<string, string> $options
|
||||
* @param string[] $selected
|
||||
* @param array<string, string> $customExtra
|
||||
*/
|
||||
function form_multiselect(
|
||||
string $name = '',
|
||||
array $options = [],
|
||||
array $selected = [],
|
||||
array $customExtra = []
|
||||
): string {
|
||||
$defaultExtra = [
|
||||
'data-class' => $customExtra['class'],
|
||||
'multiple' => 'multiple',
|
||||
];
|
||||
$extra = array_merge($defaultExtra, $customExtra);
|
||||
|
||||
return form_dropdown($name, $options, $selected, $extra);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('form_dropdown')) {
|
||||
/**
|
||||
* Drop-down Menu (based on html select tag)
|
||||
*
|
||||
* @param array<string, mixed> $options
|
||||
* @param string[] $selected
|
||||
* @param array<string|int> $selected
|
||||
* @param array<string, mixed> $customExtra
|
||||
*/
|
||||
function form_dropdown(
|
||||
|
@ -236,81 +210,3 @@ if (! function_exists('form_dropdown')) {
|
|||
return $form . "</select>\n";
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
if (! function_exists('form_editor')) {
|
||||
/**
|
||||
* Markdown editor
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
* @param array<string, mixed>|string $extra
|
||||
*/
|
||||
function form_markdown_editor(array $data = [], string $value = '', string | array $extra = ''): string
|
||||
{
|
||||
$editorClass = 'w-full flex flex-col bg-white border border-gray-500 focus-within:ring-1 focus-within:ring-blue-600';
|
||||
if (array_key_exists('class', $data) && $data['class'] !== '') {
|
||||
$editorClass .= ' ' . $data['class'];
|
||||
unset($data['class']);
|
||||
}
|
||||
|
||||
$data['class'] = 'border-none outline-none focus:border-none focus:outline-none w-full h-full';
|
||||
|
||||
return '<div class="' . $editorClass . '">' .
|
||||
'<header class="sticky top-0 z-20 flex flex-wrap justify-between bg-white border-b border-gray-500">' .
|
||||
'<markdown-write-preview for="' . $data['id'] . '" class="relative inline-flex h-8">' .
|
||||
'<button type="button" slot="write" class="px-2 font-semibold focus:outline-none focus:ring-inset focus:ring-2 focus:ring-pine-600">' . lang(
|
||||
'Common.forms.editor.write'
|
||||
) . '</button>' .
|
||||
'<button type="button" slot="preview" class="px-2 focus:outline-none focus:ring-inset focus:ring-2 focus:ring-pine-600">' . lang(
|
||||
'Common.forms.editor.preview'
|
||||
) . '</button>' .
|
||||
'</markdown-write-preview>' .
|
||||
'<markdown-toolbar for="' . $data['id'] . '" class="flex gap-4 px-2 py-1">' .
|
||||
'<div class="inline-flex text-2xl gap-x-1">' .
|
||||
'<md-header class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'heading'
|
||||
) . '</md-header>' .
|
||||
'<md-bold class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'bold'
|
||||
) . '</md-bold>' .
|
||||
'<md-italic class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'italic'
|
||||
) . '</md-italic>' .
|
||||
'</div>' .
|
||||
'<div class="inline-flex text-2xl gap-x-1">' .
|
||||
'<md-unordered-list class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'list-unordered'
|
||||
) . '</md-unordered-list>' .
|
||||
'<md-ordered-list class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'list-ordered'
|
||||
) . '</md-ordered-list>' .
|
||||
'</div>' .
|
||||
'<div class="inline-flex text-2xl gap-x-1">' .
|
||||
'<md-quote class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'quote'
|
||||
) . '</md-quote>' .
|
||||
'<md-link class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'link'
|
||||
) . '</md-link>' .
|
||||
'<md-image class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'image-add'
|
||||
) . '</md-image>' .
|
||||
'</div>' .
|
||||
'</markdown-toolbar>' .
|
||||
'</header>' .
|
||||
'<div class="relative">' .
|
||||
form_textarea($data, $value, $extra) .
|
||||
'<markdown-preview for="' . $data['id'] . '" class="absolute top-0 left-0 hidden w-full h-full p-2 overflow-y-auto prose bg-gray-50" showClass="bg-white"></markdown-preview>' .
|
||||
'</div>' .
|
||||
'<footer class="flex px-2 py-1 bg-gray-100 border-t">' .
|
||||
'<a href="https://commonmark.org/help/" class="inline-flex items-center text-xs font-semibold text-gray-500 hover:text-gray-700" target="_blank" rel="noopener noreferrer">' . icon(
|
||||
'markdown',
|
||||
'mr-1 text-lg text-gray-400'
|
||||
) . lang('Common.forms.editor.help') . '</a>' .
|
||||
'</footer>' .
|
||||
'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ViewComponents;
|
||||
|
||||
class Component implements ComponentInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $attributes = [
|
||||
'class' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $properties
|
||||
* @param array<string, string> $attributes
|
||||
*/
|
||||
public function __construct(
|
||||
protected array $properties,
|
||||
array $attributes
|
||||
) {
|
||||
// overwrite default properties if set
|
||||
foreach ($properties as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
|
||||
$this->attributes = array_merge($this->attributes, $attributes);
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return static::class . ': RENDER METHOD NOT IMPLEMENTED';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ViewComponents;
|
||||
|
||||
interface ComponentInterface
|
||||
{
|
||||
public function render(): string;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ViewComponents;
|
||||
|
||||
use ViewComponents\Config\ViewComponents;
|
||||
use ViewComponents\Exceptions\ComponentNotFoundException;
|
||||
|
||||
class ComponentLoader
|
||||
{
|
||||
protected ViewComponents $config;
|
||||
|
||||
protected string $name;
|
||||
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected array $properties = [];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $attributes = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = config('ViewComponents');
|
||||
}
|
||||
|
||||
public function __get(string $property): mixed
|
||||
{
|
||||
if (property_exists($this, $property)) {
|
||||
return $this->{$property};
|
||||
}
|
||||
}
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
public function __set(string $property, mixed $value)
|
||||
{
|
||||
if (property_exists($this, $property)) {
|
||||
$this->{$property} = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ComponentNotFoundException
|
||||
*/
|
||||
public function load(): string
|
||||
{
|
||||
// first, check if there exists a component class to load in class components path
|
||||
if (file_exists("{$this->config->classComponentsPath}/{$this->name}.php")) {
|
||||
return $this->loadComponentClass();
|
||||
}
|
||||
|
||||
// check for the existence of a view file if no component class has been found
|
||||
// component view files are camel case
|
||||
$camelCaseName = strtolower(preg_replace('~(?<!^)(?<!\/)[A-Z]~', '_$0', $this->name) ?? '');
|
||||
|
||||
if (file_exists("{$this->config->componentsViewPath}/{$camelCaseName}.php")) {
|
||||
return $this->loadComponentView($camelCaseName);
|
||||
}
|
||||
|
||||
throw new ComponentNotFoundException("Could not find component \"{$this->name}\"");
|
||||
}
|
||||
|
||||
private function loadComponentClass(): string
|
||||
{
|
||||
$classComponentsNamespace = $this->config->classComponentsNamespace;
|
||||
|
||||
$namespacedName = str_replace('/', '\\', $this->name);
|
||||
$componentClassNamespace = "{$classComponentsNamespace}\\{$namespacedName}";
|
||||
|
||||
$component = new $componentClassNamespace($this->properties, $this->attributes);
|
||||
return $component->render();
|
||||
}
|
||||
|
||||
private function loadComponentView(string $name): string
|
||||
{
|
||||
$viewData = [...$this->properties, ...$this->attributes];
|
||||
|
||||
return view("components/{$name}", $viewData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ViewComponents\Config;
|
||||
|
||||
use CodeIgniter\Config\BaseService;
|
||||
use ViewComponents\ComponentLoader;
|
||||
|
||||
/**
|
||||
* Services Configuration file.
|
||||
*
|
||||
* Services are simply other classes/libraries that the system uses to do its job. This is used by CodeIgniter to allow
|
||||
* the core of the framework to be swapped out easily without affecting the usage within the rest of your application.
|
||||
*
|
||||
* This file holds any application-specific services, or service overrides that you might need. An example has been
|
||||
* included with the general method format you should use for your service methods. For more examples, see the core
|
||||
* Services file at system/Config/Services.php.
|
||||
*/
|
||||
class Services extends BaseService
|
||||
{
|
||||
public static function viewcomponents(bool $getShared = true): ComponentLoader
|
||||
{
|
||||
if ($getShared) {
|
||||
return self::getSharedInstance('viewcomponents');
|
||||
}
|
||||
|
||||
return new ComponentLoader();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ViewComponents\Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class ViewComponents extends BaseConfig
|
||||
{
|
||||
public string $classComponentsNamespace = APP_NAMESPACE . '\View\Components';
|
||||
|
||||
public string $classComponentsPath = APPPATH . 'View/Components';
|
||||
|
||||
public string $componentsViewPath = APPPATH . 'Views/components';
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ViewComponents\Exceptions;
|
||||
|
||||
use CodeIgniter\Exceptions\ExceptionInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class ComponentNotFoundException extends RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
*/
|
||||
|
||||
if (! function_exists('component')) {
|
||||
/**
|
||||
* Loads the specified class or view file component in the parameters
|
||||
*
|
||||
* @param array<string, array<string, mixed>> $properties
|
||||
* @param array<string, array<string, mixed>> $attributes
|
||||
*/
|
||||
function component(string $name, array $properties = [], array $attributes = []): string
|
||||
{
|
||||
$componentLoader = service('viewcomponents');
|
||||
|
||||
$componentLoader->name = $name;
|
||||
$componentLoader->properties = $properties;
|
||||
$componentLoader->attributes = $attributes;
|
||||
|
||||
return $componentLoader->load();
|
||||
}
|
||||
}
|
|
@ -60,6 +60,10 @@ export class XMLEditor extends LitElement {
|
|||
border: 1px solid #6b7280;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.cm-editor.cm-focused {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: 0 0 0 1px #2563eb;
|
||||
}
|
||||
`;
|
||||
|
||||
render(): TemplateResult<1> {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class Button extends Component
|
||||
{
|
||||
protected string $label = '';
|
||||
|
||||
protected string $uri = '';
|
||||
|
||||
protected string $variant = 'default';
|
||||
|
||||
protected string $size = 'base';
|
||||
|
||||
protected string $iconLeft = '';
|
||||
|
||||
protected string $iconRight = '';
|
||||
|
||||
protected bool $isSquared = false;
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$baseClass =
|
||||
'inline-flex items-center font-semibold shadow-xs rounded-full focus:outline-none focus:ring';
|
||||
|
||||
$variantClass = [
|
||||
'default' => 'text-black bg-gray-300 hover:bg-gray-400',
|
||||
'primary' => 'text-white bg-pine-700 hover:bg-pine-800',
|
||||
'secondary' => 'text-white bg-gray-700 hover:bg-gray-800',
|
||||
'accent' => 'text-white bg-rose-600 hover:bg-rose-800',
|
||||
'success' => 'text-white bg-green-600 hover:bg-green-700',
|
||||
'danger' => 'text-white bg-red-600 hover:bg-red-700',
|
||||
'warning' => 'text-black bg-yellow-500 hover:bg-yellow-600',
|
||||
'info' => 'text-white bg-blue-500 hover:bg-blue-600',
|
||||
];
|
||||
|
||||
$sizeClass = [
|
||||
'small' => 'text-xs md:text-sm',
|
||||
'base' => 'text-sm md:text-base',
|
||||
'large' => 'text-lg md:text-xl',
|
||||
];
|
||||
|
||||
$basePaddings = [
|
||||
'small' => 'px-2 md:px-3 md:py-1',
|
||||
'base' => 'px-3 py-1 md:px-4 md:py-2',
|
||||
'large' => 'px-3 py-2 md:px-5',
|
||||
];
|
||||
|
||||
$squaredPaddings = [
|
||||
'small' => 'p-1',
|
||||
'base' => 'p-2',
|
||||
'large' => 'p-3',
|
||||
];
|
||||
|
||||
$buttonClass =
|
||||
$baseClass .
|
||||
' ' .
|
||||
($this->isSquared
|
||||
? $squaredPaddings[$this->size]
|
||||
: $basePaddings[$this->size]) .
|
||||
' ' .
|
||||
$sizeClass[$this->size] .
|
||||
' ' .
|
||||
$variantClass[$this->variant];
|
||||
|
||||
if (array_key_exists('class', $this->attributes)) {
|
||||
$buttonClass .= ' ' . $this->attributes['class'];
|
||||
unset($this->attributes['class']);
|
||||
}
|
||||
|
||||
if ($this->iconLeft !== '') {
|
||||
$this->label = icon($this->iconLeft, 'mr-2') . $this->label;
|
||||
}
|
||||
|
||||
if ($this->iconRight !== '') {
|
||||
$this->label .= icon($this->iconRight, 'ml-2');
|
||||
}
|
||||
|
||||
if ($this->uri !== '') {
|
||||
return anchor($this->uri, $this->label, array_merge([
|
||||
'class' => $buttonClass,
|
||||
], $this->attributes));
|
||||
}
|
||||
|
||||
$defaultButtonAttributes = [
|
||||
'type' => 'button',
|
||||
];
|
||||
$attributes = stringify_attributes(array_merge($defaultButtonAttributes, $this->attributes));
|
||||
|
||||
return <<<CODE_SAMPLE
|
||||
<button class="{$buttonClass}" {$attributes}>{$this->label}</button>
|
||||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class Input extends Component
|
||||
{
|
||||
public function render(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class Label extends Component
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $attributes = [
|
||||
'for' => '',
|
||||
'name' => '',
|
||||
'value' => '',
|
||||
'class' => '',
|
||||
];
|
||||
|
||||
protected string $text = '';
|
||||
|
||||
protected string $hint = '';
|
||||
|
||||
protected bool $isOptional = false;
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$labelClass = $this->attributes['class'];
|
||||
unset($this->attributes['class']);
|
||||
|
||||
$attributes = stringify_attributes($this->attributes);
|
||||
$optionalText = $this->isOptional ? '<small class="ml-1 lowercase">(' .
|
||||
lang('Common.optional') .
|
||||
')</small>' : '';
|
||||
$hint = $this->hint !== '' ? hint_tooltip($this->hint, 'ml-1') : '';
|
||||
|
||||
return <<<CODE_SAMPLE
|
||||
<label class="{$labelClass}" {$attributes}>{$this->text}{$optionalText}{$hint}</label>
|
||||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class MarkdownEditor extends Component
|
||||
{
|
||||
protected string $content = '';
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$editorClass = 'w-full flex flex-col bg-white border border-gray-500 focus-within:ring-1 focus-within:ring-blue-600';
|
||||
if ($this->attributes['class'] !== '') {
|
||||
$editorClass .= ' ' . $this->attributes['class'];
|
||||
unset($this->attributes['class']);
|
||||
}
|
||||
|
||||
$this->attributes['class'] = 'border-none outline-none focus:border-none focus:outline-none w-full h-full';
|
||||
|
||||
return '<div class="' . $editorClass . '">' .
|
||||
'<header class="sticky top-0 z-20 flex flex-wrap justify-between bg-white border-b border-gray-500">' .
|
||||
'<markdown-write-preview for="' . $this->attributes['id'] . '" class="relative inline-flex h-8">' .
|
||||
'<button type="button" slot="write" class="px-2 font-semibold focus:outline-none focus:ring-inset focus:ring-2 focus:ring-pine-600">' . lang(
|
||||
'Common.forms.editor.write'
|
||||
) . '</button>' .
|
||||
'<button type="button" slot="preview" class="px-2 focus:outline-none focus:ring-inset focus:ring-2 focus:ring-pine-600">' . lang(
|
||||
'Common.forms.editor.preview'
|
||||
) . '</button>' .
|
||||
'</markdown-write-preview>' .
|
||||
'<markdown-toolbar for="' . $this->attributes['id'] . '" class="flex gap-4 px-2 py-1">' .
|
||||
'<div class="inline-flex text-2xl gap-x-1">' .
|
||||
'<md-header class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'heading'
|
||||
) . '</md-header>' .
|
||||
'<md-bold class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'bold'
|
||||
) . '</md-bold>' .
|
||||
'<md-italic class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'italic'
|
||||
) . '</md-italic>' .
|
||||
'</div>' .
|
||||
'<div class="inline-flex text-2xl gap-x-1">' .
|
||||
'<md-unordered-list class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'list-unordered'
|
||||
) . '</md-unordered-list>' .
|
||||
'<md-ordered-list class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'list-ordered'
|
||||
) . '</md-ordered-list>' .
|
||||
'</div>' .
|
||||
'<div class="inline-flex text-2xl gap-x-1">' .
|
||||
'<md-quote class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'quote'
|
||||
) . '</md-quote>' .
|
||||
'<md-link class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'link'
|
||||
) . '</md-link>' .
|
||||
'<md-image class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">' . icon(
|
||||
'image-add'
|
||||
) . '</md-image>' .
|
||||
'</div>' .
|
||||
'</markdown-toolbar>' .
|
||||
'</header>' .
|
||||
'<div class="relative">' .
|
||||
form_textarea($this->attributes, $this->content) .
|
||||
'<markdown-preview for="' . $this->attributes['id'] . '" class="absolute top-0 left-0 hidden w-full h-full p-2 overflow-y-auto prose bg-gray-50" showClass="bg-white"></markdown-preview>' .
|
||||
'</div>' .
|
||||
'<footer class="flex px-2 py-1 bg-gray-100 border-t">' .
|
||||
'<a href="https://commonmark.org/help/" class="inline-flex items-center text-xs font-semibold text-gray-500 hover:text-gray-700" target="_blank" rel="noopener noreferrer">' . icon(
|
||||
'markdown',
|
||||
'mr-1 text-lg text-gray-400'
|
||||
) . lang('Common.forms.editor.help') . '</a>' .
|
||||
'</footer>' .
|
||||
'</div>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class MultiSelect extends Component
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $selected = [];
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$defaultAttributes = [
|
||||
'data-class' => $this->attributes['class'],
|
||||
'multiple' => 'multiple',
|
||||
];
|
||||
$extra = array_merge($defaultAttributes, $this->attributes);
|
||||
|
||||
return form_dropdown($this->attributes['name'], $this->options, $this->selected, $extra);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class MultiSelect extends Component
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $selected = [];
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$defaultAttributes = [
|
||||
'data-class' => $this->attributes['class'],
|
||||
'multiple' => 'multiple',
|
||||
];
|
||||
$extra = array_merge($defaultAttributes, $this->attributes);
|
||||
|
||||
return form_dropdown($this->attributes['name'], $this->options, $this->selected, $extra);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
/**
|
||||
* Form Checkbox Switch
|
||||
*
|
||||
* Abstracts form_label to stylize it as a switch toggle
|
||||
*/
|
||||
class Toggler extends Component
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $attributes = [
|
||||
'id' => '',
|
||||
'name' => '',
|
||||
'value' => '',
|
||||
'class' => '',
|
||||
];
|
||||
|
||||
protected string $label = '';
|
||||
|
||||
protected string $hint = '';
|
||||
|
||||
protected bool $checked = false;
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$wrapperClass = $this->attributes['class'];
|
||||
unset($this->attributes['class']);
|
||||
|
||||
$this->attributes['class'] = 'form-switch';
|
||||
|
||||
$checkbox = form_checkbox($this->attributes, $this->attributes['value'], $this->checked);
|
||||
$hint = $this->hint !== '' ? hint_tooltip(lang('Podcast.form.lock_hint'), 'ml-1') : '';
|
||||
return <<<CODE_SAMPLE
|
||||
<label class="relative inline-flex items-center {$wrapperClass}">
|
||||
{$checkbox}
|
||||
<span class="form-switch-slider"></span>
|
||||
<span class="ml-2">{$this->label}{$hint}</span>
|
||||
</label>
|
||||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class XMLEditor extends Component
|
||||
{
|
||||
protected string $content = '';
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $attributes = [
|
||||
'slot' => 'textarea',
|
||||
'rows' => '5',
|
||||
'class' => 'textarea',
|
||||
];
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$textarea = form_textarea($this->attributes, $this->content);
|
||||
|
||||
return <<<CODE_SAMPLE
|
||||
<xml-editor>{$textarea}</time-ago>
|
||||
CODE_SAMPLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class Icon extends Component
|
||||
{
|
||||
public string $glyph = '';
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$svgContents = file_get_contents('assets/icons/' . $this->glyph . '.svg');
|
||||
|
||||
if ($svgContents) {
|
||||
if ($this->attributes['class'] !== '') {
|
||||
$svgContents = str_replace('<svg', '<svg class="' . $this->attributes['class'] . '"', $svgContents);
|
||||
}
|
||||
|
||||
return $svgContents;
|
||||
}
|
||||
|
||||
return '□';
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_label(lang('Contributor.form.user'), 'user') ?>
|
||||
<?= component('Forms/Label', ['text' => lang('Contributor.form.user')], ['for' => 'user']) ?>
|
||||
<?= form_dropdown('user', $userOptions, [old('user', '')], [
|
||||
'id' => 'user',
|
||||
'class' => 'form-select mb-4',
|
||||
|
@ -24,7 +24,7 @@
|
|||
'placeholder' => lang('Contributor.form.user_placeholder')
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Contributor.form.role'), 'role') ?>
|
||||
<?= component('Forms/Label', ['text' => lang('Contributor.form.role')], ['for' => 'role']) ?>
|
||||
<?= form_dropdown('role', $roleOptions, [old('role', '')], [
|
||||
'id' => 'role',
|
||||
'class' => 'form-select mb-4',
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
]) ?>
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_label(lang('Contributor.form.role'), 'role') ?>
|
||||
<?= component('Forms/Label', ['text' => lang('Contributor.form.role')], ['for' => 'role']) ?>
|
||||
<?= form_dropdown('role', $roleOptions, [old('role', $contributorGroupId)], [
|
||||
'id' => 'role',
|
||||
'class' => 'form-select mb-4',
|
||||
|
|
|
@ -28,11 +28,10 @@
|
|||
lang('Episode.form.info_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.audio_file'),
|
||||
'audio_file',
|
||||
[],
|
||||
lang('Episode.form.audio_file_hint'),
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' => lang('Episode.form.audio_file'), 'hint' => lang('Episode.form.audio_file_hint')],
|
||||
['for' => 'audio_file'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'audio_file',
|
||||
|
@ -43,12 +42,14 @@
|
|||
'accept' => '.mp3,.m4a',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.image'),
|
||||
'image',
|
||||
[],
|
||||
lang('Episode.form.image_hint'),
|
||||
true,
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.image'),
|
||||
'hint' => lang('Episode.form.image_hint'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'image'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
|
@ -61,11 +62,11 @@
|
|||
'Common.forms.image_size_hint',
|
||||
) ?></small>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.title'),
|
||||
'title',
|
||||
[],
|
||||
lang('Episode.form.title_hint'),
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' => lang('Episode.form.title'),
|
||||
'hint' => lang('Episode.form.title_hint')],
|
||||
['for' => 'title'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'title',
|
||||
|
@ -76,10 +77,10 @@
|
|||
'data-slugify' => 'title',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.permalink'),
|
||||
'slug',
|
||||
[],
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' => lang('Episode.form.permalink')],
|
||||
['for' => 'slug']
|
||||
) ?>
|
||||
<permalink-edit class="inline-flex items-center mb-4 text-xs" edit-label="<?= lang('Common.edit') ?>" copy-label="<?= lang('Common.copy') ?>" copied-label="<?= lang('Common.copied') ?>">
|
||||
<span slot="domain"><?= base_url('/@'. $podcast->handle . '/episodes' ) . '/' ?></span>
|
||||
|
@ -96,7 +97,7 @@
|
|||
|
||||
<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') ?>
|
||||
<?= component('Forms/Label', ['text' => lang('Episode.form.season_number')], ['for' => 'season_number']) ?>
|
||||
<?= form_input([
|
||||
'id' => 'season_number',
|
||||
'name' => 'season_number',
|
||||
|
@ -106,7 +107,7 @@
|
|||
]) ?>
|
||||
</div>
|
||||
<div class="flex flex-col flex-1">
|
||||
<?= form_label(lang('Episode.form.episode_number'), 'episode_number') ?>
|
||||
<?= component('Forms/Label', ['text' => lang('Episode.form.episode_number')], ['for' => 'episode_number']) ?>
|
||||
<?= form_input([
|
||||
'id' => 'episode_number',
|
||||
'name' => 'episode_number',
|
||||
|
@ -203,36 +204,45 @@
|
|||
) ?>
|
||||
|
||||
<div class="mb-4">
|
||||
<?= form_label(lang('Episode.form.description'), 'description') ?>
|
||||
<?= form_markdown_editor(
|
||||
<?= component('Forms/Label', ['text' => lang('Episode.form.description')], ['for' => 'description']) ?>
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old('description', '', false),
|
||||
],
|
||||
[
|
||||
'id' => 'description',
|
||||
'name' => 'description',
|
||||
'required' => 'required',
|
||||
],
|
||||
old('description', '', false),
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<?= form_label(
|
||||
lang('Episode.form.description_footer'),
|
||||
'description_footer',
|
||||
[],
|
||||
lang('Episode.form.description_footer_hint'),
|
||||
true
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.description_footer'),
|
||||
'hint' => lang('Episode.form.description_footer_hint'),
|
||||
'isOptional' => true
|
||||
],
|
||||
[
|
||||
'for' => 'description_footer'
|
||||
],
|
||||
) ?>
|
||||
<?= form_markdown_editor(
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old(
|
||||
'description_footer',
|
||||
$podcast->episode_description_footer_markdown ?? '',
|
||||
false,
|
||||
),
|
||||
],
|
||||
[
|
||||
'id' => 'description_footer',
|
||||
'name' => 'description_footer',
|
||||
'rows' => 6
|
||||
],
|
||||
old(
|
||||
'description_footer',
|
||||
$podcast->episode_description_footer_markdown ?? '',
|
||||
false,
|
||||
),
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
|
@ -243,12 +253,13 @@
|
|||
lang('Episode.form.location_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.location_name'),
|
||||
'location_name',
|
||||
[],
|
||||
lang('Episode.form.location_name_hint'),
|
||||
true,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.location_name'),
|
||||
'hint' => lang('Episode.form.location_name_hint'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'location_name'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'location_name',
|
||||
|
@ -290,12 +301,12 @@
|
|||
|
||||
<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,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.transcript_file'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'transcript_file', 'class' => 'sr-only'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'transcript_file',
|
||||
|
@ -306,12 +317,12 @@
|
|||
]) ?>
|
||||
</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,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.transcript_file_remote_url'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'transcript_file_remote_url', 'class' => 'sr-only'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'transcript_file_remote_url',
|
||||
|
@ -353,12 +364,12 @@
|
|||
|
||||
<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,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.chapters_file'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'chapters_file', 'class' => 'sr-only'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'chapters_file',
|
||||
|
@ -369,12 +380,15 @@
|
|||
]) ?>
|
||||
</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,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.chapters_file_remote_url'),
|
||||
'isOptional' => true
|
||||
],
|
||||
[
|
||||
'for' => 'chapters_file_remote_url',
|
||||
'class' => 'sr-only'
|
||||
],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'chapters_file_remote_url',
|
||||
|
@ -395,27 +409,37 @@
|
|||
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,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.custom_rss'),
|
||||
'hint' => lang('Episode.form.custom_rss_hint'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'custom_rss']
|
||||
) ?>
|
||||
<?= component('Forms/XMLEditor',
|
||||
[
|
||||
'content' => old('custom_rss', '')
|
||||
],
|
||||
[
|
||||
'id' => 'custom_rss',
|
||||
'name' => 'custom_rss',
|
||||
]
|
||||
) ?>
|
||||
<?= xml_editor([
|
||||
'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),
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Episode.form.block'),
|
||||
'hint' => lang('Episode.form.block_hint')
|
||||
],
|
||||
[
|
||||
'id' => 'block',
|
||||
'name' => 'block',
|
||||
'value' => 'yes',
|
||||
'checked' => old('block', false),
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= button(
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<?= 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') ?>
|
||||
<?= icon('alert', 'mr-2 text-lg flex-shrink-0') .
|
||||
lang('Episode.form.warning') ?>
|
||||
</div>
|
||||
|
||||
<?= form_section(
|
||||
|
@ -35,11 +35,11 @@
|
|||
/>',
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.audio_file'),
|
||||
'audio_file',
|
||||
[],
|
||||
lang('Episode.form.audio_file_hint'),
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' =>
|
||||
lang('Episode.form.audio_file'), 'hint' => lang('Episode.form.audio_file_hint'),],
|
||||
['for' => 'audio_file'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'audio_file',
|
||||
|
@ -49,12 +49,12 @@
|
|||
'accept' => '.mp3,.m4a',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.image'),
|
||||
'image',
|
||||
[],
|
||||
lang('Episode.form.image_hint'),
|
||||
true,
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' =>
|
||||
lang('Episode.form.image'), 'hint' => lang('Episode.form.image_hint'), 'isOptional' => true,],
|
||||
['for' =>
|
||||
'image',]
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
|
@ -68,11 +68,12 @@
|
|||
'Common.forms.image_size_hint',
|
||||
) ?></small>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.title'),
|
||||
'title',
|
||||
[],
|
||||
lang('Episode.form.title_hint'),
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' =>
|
||||
lang('Episode.form.title'), 'hint' => lang('Episode.form.title_hint'),],
|
||||
['for' =>
|
||||
'title',]
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'title',
|
||||
|
@ -83,27 +84,29 @@
|
|||
'data-slugify' => 'title',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.permalink'),
|
||||
'slug',
|
||||
[],
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.permalink')
|
||||
],
|
||||
['for' => 'slug',]
|
||||
) ?>
|
||||
<permalink-edit class="inline-flex items-center mb-4 text-xs" edit-label="<?= lang('Common.edit') ?>" copy-label="<?= lang('Common.copy') ?>" copied-label="<?= lang('Common.copied') ?>">
|
||||
<span slot="domain"><?= base_url('/@'. $podcast->handle . '/episodes' ) . '/' ?></span>
|
||||
<span slot="domain"><?= base_url('/@' . $podcast->handle . '/episodes') . '/' ?></span>
|
||||
<?= form_input([
|
||||
'id' => 'slug',
|
||||
'name' => 'slug',
|
||||
'class' => 'form-input flex-1 w-0 text-xs',
|
||||
'value' => old('slug', $episode->slug),
|
||||
'required' => 'required',
|
||||
'data-slugify' => 'slug',
|
||||
'slot' => 'slug-input'
|
||||
'id' => 'slug',
|
||||
'name' => 'slug',
|
||||
'class' => 'form-input flex-1 w-0 text-xs',
|
||||
'value' => old('slug', $episode->slug),
|
||||
'required' => 'required',
|
||||
'data-slugify' => 'slug',
|
||||
'slot' => 'slug-input'
|
||||
]) ?>
|
||||
</permalink-edit>
|
||||
|
||||
<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') ?>
|
||||
<?= component('Forms/Label', ['text' => lang('Episode.form.season_number')], ['for' => 'season_number']) ?>
|
||||
<?= form_input([
|
||||
'id' => 'season_number',
|
||||
'name' => 'season_number',
|
||||
|
@ -113,7 +116,7 @@
|
|||
]) ?>
|
||||
</div>
|
||||
<div class="flex flex-col flex-1">
|
||||
<?= form_label(lang('Episode.form.episode_number'), 'episode_number') ?>
|
||||
<?= component('Forms/Label', ['text' => lang('Episode.form.episode_number')], ['for' => 'episode_number']) ?>
|
||||
<?= form_input([
|
||||
'id' => 'episode_number',
|
||||
'name' => 'episode_number',
|
||||
|
@ -125,83 +128,83 @@
|
|||
</div>
|
||||
|
||||
<?= form_fieldset('', ['class' => 'flex mb-4 gap-1']) ?>
|
||||
<legend>
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
</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() ?>
|
||||
|
@ -213,36 +216,43 @@
|
|||
) ?>
|
||||
|
||||
<div class="mb-4">
|
||||
<?= form_label(lang('Episode.form.description'), 'description') ?>
|
||||
<?= form_markdown_editor(
|
||||
<?= component('Forms/Label', ['text' => lang('Episode.form.description')], ['for' => 'description']) ?>
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old('description', $episode->description_markdown, false),
|
||||
],
|
||||
[
|
||||
'id' => 'description',
|
||||
'name' => 'description',
|
||||
'required' => 'required',
|
||||
],
|
||||
old('description', $episode->description_markdown, false),
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<?= form_label(
|
||||
lang('Episode.form.description_footer'),
|
||||
'description_footer',
|
||||
[],
|
||||
lang('Episode.form.description_footer_hint'),
|
||||
true
|
||||
<?= component('Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.description_footer'),
|
||||
'hint' => lang('Episode.form.description_footer_hint'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'description_footer'],
|
||||
) ?>
|
||||
<?= form_markdown_editor(
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old(
|
||||
'description_footer',
|
||||
$podcast->episode_description_footer_markdown ?? '',
|
||||
false,
|
||||
),
|
||||
],
|
||||
[
|
||||
'id' => 'description_footer',
|
||||
'name' => 'description_footer',
|
||||
'rows' => 6
|
||||
],
|
||||
old(
|
||||
'description_footer',
|
||||
$podcast->episode_description_footer_markdown ?? '',
|
||||
false,
|
||||
),
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
|
@ -253,12 +263,13 @@
|
|||
lang('Episode.form.location_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Episode.form.location_name'),
|
||||
'location_name',
|
||||
[],
|
||||
lang('Episode.form.location_name_hint'),
|
||||
true,
|
||||
<?= component('Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.location_name'),
|
||||
'hint' => lang('Episode.form.location_name_hint'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'location_name']
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'location_name',
|
||||
|
@ -273,34 +284,34 @@
|
|||
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>”',
|
||||
'“<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>
|
||||
<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>
|
||||
<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="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,
|
||||
|
@ -321,7 +332,7 @@
|
|||
icon('delete-bin', 'mx-auto'),
|
||||
[
|
||||
'class' =>
|
||||
'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900',
|
||||
'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900',
|
||||
'data-toggle' => 'tooltip',
|
||||
'data-placement' => 'bottom',
|
||||
'title' => lang(
|
||||
|
@ -331,12 +342,12 @@
|
|||
) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?= form_label(
|
||||
lang('Episode.form.transcript_file'),
|
||||
'transcript_file',
|
||||
['class' => 'sr-only'],
|
||||
lang('Episode.form.transcript_file'),
|
||||
true,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.transcript_file'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'transcript_file', 'class' => 'sr-only'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'transcript_file',
|
||||
|
@ -345,14 +356,14 @@
|
|||
'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,
|
||||
</section>
|
||||
<section id="transcript-file-remote-url" class="tab-panel">
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.transcript_file_remote_url'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'transcript_file_remote_url', 'class' => 'sr-only'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'transcript_file_remote_url',
|
||||
|
@ -365,35 +376,35 @@
|
|||
$episode->transcript_file_remote_url,
|
||||
),
|
||||
]) ?>
|
||||
</section>
|
||||
</div>
|
||||
</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>
|
||||
<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>
|
||||
<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="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,
|
||||
|
@ -413,7 +424,7 @@
|
|||
icon('delete-bin', 'mx-auto'),
|
||||
[
|
||||
'class' =>
|
||||
'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900',
|
||||
'p-1 bg-red-200 rounded-full text-red-700 hover:text-red-900',
|
||||
'data-toggle' => 'tooltip',
|
||||
'data-placement' => 'bottom',
|
||||
'title' => lang(
|
||||
|
@ -423,12 +434,12 @@
|
|||
) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?= form_label(
|
||||
lang('Episode.form.chapters_file'),
|
||||
'chapters_file',
|
||||
['class' => 'sr-only'],
|
||||
lang('Episode.form.chapters_file'),
|
||||
true,
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.chapters_file'),
|
||||
'isOptional' => true
|
||||
],
|
||||
['for' => 'chapters_file', 'class' => 'sr-only'],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'chapters_file',
|
||||
|
@ -437,14 +448,17 @@
|
|||
'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,
|
||||
</section>
|
||||
<section id="chapters-file-remote-url" class="tab-panel">
|
||||
<?= component( 'Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.chapters_file_remote_url'),
|
||||
'isOptional' => true
|
||||
],
|
||||
[
|
||||
'for' => 'chapters_file_remote_url',
|
||||
'class' => 'sr-only'
|
||||
],
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'chapters_file_remote_url',
|
||||
|
@ -457,9 +471,9 @@
|
|||
$episode->chapters_file_remote_url,
|
||||
),
|
||||
]) ?>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<?= form_fieldset_close() ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
@ -468,27 +482,39 @@
|
|||
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,
|
||||
<?= component('Forms/Label',
|
||||
[
|
||||
'text' => lang('Episode.form.custom_rss'),
|
||||
'hint' => lang('Episode.form.custom_rss_hint'),
|
||||
'isOptional' => true,
|
||||
],
|
||||
[
|
||||
'for' => 'custom_rss',
|
||||
]
|
||||
) ?>
|
||||
<?= component('Forms/XMLEditor',
|
||||
[
|
||||
'content' => old('custom_rss', $episode->custom_rss_string)
|
||||
],
|
||||
[
|
||||
'id' => 'custom_rss',
|
||||
'name' => 'custom_rss',
|
||||
]
|
||||
) ?>
|
||||
<?= xml_editor([
|
||||
'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),
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Episode.form.block'),
|
||||
'hint' => lang('Episode.form.block_hint')
|
||||
],
|
||||
[
|
||||
'id' => 'block',
|
||||
'name' => 'block',
|
||||
'value' => 'yes',
|
||||
'checked' => old('block', $episode->is_blocked),
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= button(
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?= form_label(lang('Episode.embeddable_player.label'), 'label') ?>
|
||||
<p><?= lang('Episode.embeddable_player.label') ?></p>
|
||||
|
||||
<div class="flex w-full mt-6 mb-6">
|
||||
<?php foreach ($themes as $themeKey => $theme): ?>
|
||||
|
|
|
@ -60,8 +60,8 @@
|
|||
($person->information_url === null
|
||||
? ''
|
||||
: "<a href=\"{$person->information_url}\" target=\"_blank\" rel=\"noreferrer noopener\" class=\"text-sm text-blue-800 hover:underline\">" .
|
||||
$person->information_url .
|
||||
'</a>') .
|
||||
$person->information_url .
|
||||
'</a>') .
|
||||
'</div></div>';
|
||||
},
|
||||
],
|
||||
|
@ -95,40 +95,36 @@
|
|||
lang('Person.episode_form.add_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Person.episode_form.persons'),
|
||||
'persons',
|
||||
[],
|
||||
lang('Person.episode_form.persons_hint'),
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' => lang('Person.episode_form.persons'), 'hint' => lang('Person.episode_form.persons_hint')],
|
||||
['for' => 'persons'],
|
||||
) ?>
|
||||
<?= form_multiselect('persons[]', $personOptions, old('persons', []), [
|
||||
<?= component('Forms/MultiSelect', ['options' => $personOptions, 'selected' => old('persons', [])], [
|
||||
'id' => 'persons',
|
||||
'class' => 'form-select mb-4',
|
||||
'name' => 'persons[]',
|
||||
'class' => 'mb-4',
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Person.episode_form.roles'),
|
||||
'roles',
|
||||
[],
|
||||
lang('Person.episode_form.roles_hint'),
|
||||
true,
|
||||
<?= component(
|
||||
'Forms/Label',
|
||||
['text' => lang('Person.episode_form.roles'), 'hint' => lang('Person.episode_form.roles_hint'), 'isOptional' => true],
|
||||
['for' => 'roles'],
|
||||
) ?>
|
||||
<?= form_multiselect(
|
||||
'roles[]',
|
||||
$taxonomyOptions,
|
||||
old('roles', []),
|
||||
['id' => 'roles', 'class' => 'form-select mb-4'],
|
||||
) ?>
|
||||
|
||||
|
||||
<?= component('Forms/MultiSelect', ['options' => $taxonomyOptions, 'selected' => old('roles', [])], [
|
||||
'id' => 'roles',
|
||||
'name' => 'roles[]',
|
||||
'class' => 'mb-4',
|
||||
]) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
<?= button(
|
||||
lang('Person.episode_form.submit_add'),
|
||||
'',
|
||||
['variant' => 'primary'],
|
||||
['type' => 'submit', 'class' => 'self-end'],
|
||||
) ?>
|
||||
) ?>
|
||||
<?= form_close() ?>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<?= lang('Episode.publish_edit') ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?= anchor(
|
||||
|
@ -33,14 +32,11 @@
|
|||
<small class="max-w-md mb-2 text-gray-600"><?= lang('Episode.publish_form.post_hint') ?></small>
|
||||
<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" />
|
||||
<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>
|
||||
<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>
|
||||
<?= relative_time($post->published_at, 'text-xs text-gray-500') ?>
|
||||
</div>
|
||||
|
@ -85,17 +81,17 @@
|
|||
</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>
|
||||
'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>
|
||||
'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>
|
||||
'heart',
|
||||
'text-xl mr-1 text-gray-400',
|
||||
) . '0' ?></span>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
@ -151,10 +147,10 @@
|
|||
'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>
|
||||
'Episode.publish_form.scheduled_publication_date_clear',
|
||||
) ?>" title="<?= lang(
|
||||
'Episode.publish_form.scheduled_publication_date_clear',
|
||||
) ?>" data-clear=""><?= icon('close') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -46,14 +46,17 @@
|
|||
|
||||
<div class="mb-4">
|
||||
<?= form_label(lang('Page.form.content'), 'content') ?>
|
||||
<?= form_markdown_editor(
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old('content', '', false)
|
||||
],
|
||||
[
|
||||
'id' => 'content',
|
||||
'name' => 'content',
|
||||
'required' => 'required',
|
||||
'rows' => 20
|
||||
],
|
||||
old('content', '', false),
|
||||
['rows' => '20']
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -46,13 +46,16 @@
|
|||
|
||||
<div class="mb-4">
|
||||
<?= form_label(lang('Page.form.content'), 'content') ?>
|
||||
<?= form_markdown_editor(
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old('content', $page->content_markdown, false),
|
||||
],
|
||||
[
|
||||
'id' => 'content',
|
||||
'name' => 'content',
|
||||
'required' => 'required',
|
||||
],
|
||||
old('content', $page->content_markdown, false),
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -82,13 +82,16 @@
|
|||
|
||||
<div class="mb-4">
|
||||
<?= form_label(lang('Podcast.form.description'), 'description') ?>
|
||||
<?= form_markdown_editor(
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old('description', '', false),
|
||||
],
|
||||
[
|
||||
'id' => 'description',
|
||||
'name' => 'description',
|
||||
'required' => 'required',
|
||||
],
|
||||
old('description', '', false),
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
|
@ -122,16 +125,12 @@
|
|||
'',
|
||||
true,
|
||||
) ?>
|
||||
<?= form_multiselect(
|
||||
'other_categories[]',
|
||||
$categoryOptions,
|
||||
[old('other_categories', '')],
|
||||
[
|
||||
'id' => 'other_categories',
|
||||
'class' => 'mb-4',
|
||||
'data-max-item-count' => '2',
|
||||
],
|
||||
) ?>
|
||||
<?= component('Forms/MultiSelect', ['options' => $categoryOptions, 'selected' => old('other_categories', [])], [
|
||||
'id' => 'other_categories',
|
||||
'name' => 'other_categories[]',
|
||||
'class' => 'mb-4',
|
||||
'data-max-item-count' => '2',
|
||||
]) ?>
|
||||
|
||||
<?= form_fieldset('', ['class' => 'mb-4']) ?>
|
||||
<legend>
|
||||
|
@ -340,12 +339,15 @@
|
|||
lang('Podcast.form.custom_rss_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= xml_editor([
|
||||
'id' => 'custom_rss',
|
||||
'name' => 'custom_rss',
|
||||
'class' => 'form-textarea',
|
||||
'value' => old('custom_rss'),
|
||||
]) ?>
|
||||
<?= component('Forms/XMLEditor',
|
||||
[
|
||||
'content' => old('custom_rss', '')
|
||||
],
|
||||
[
|
||||
'id' => 'custom_rss',
|
||||
'name' => 'custom_rss',
|
||||
]
|
||||
) ?>
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= form_section(
|
||||
|
@ -353,28 +355,46 @@
|
|||
lang('Podcast.form.status_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_switch(
|
||||
lang('Podcast.form.block'),
|
||||
['id' => 'block', 'name' => 'block'],
|
||||
'yes',
|
||||
old('block', false),
|
||||
'mb-2',
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Podcast.form.lock'),
|
||||
'hint' => lang('Podcast.form.lock_hint'),
|
||||
],
|
||||
[
|
||||
'id' => 'lock',
|
||||
'name' => 'lock',
|
||||
'value' => 'yes',
|
||||
'checked' => old('complete', true),
|
||||
'class' => 'mb-2'
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_switch(
|
||||
lang('Podcast.form.complete'),
|
||||
['id' => 'complete', 'name' => 'complete'],
|
||||
'yes',
|
||||
old('complete', false),
|
||||
'mb-2',
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Podcast.form.block'),
|
||||
],
|
||||
[
|
||||
'id' => 'block',
|
||||
'name' => 'block',
|
||||
'value' => 'yes',
|
||||
'checked' => old('block', false),
|
||||
'class' => 'mb-2'
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_switch(
|
||||
lang('Podcast.form.lock') .
|
||||
hint_tooltip(lang('Podcast.form.lock_hint'), 'ml-1'),
|
||||
['id' => 'lock', 'name' => 'lock'],
|
||||
'yes',
|
||||
old('lock', true),
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Podcast.form.complete'),
|
||||
],
|
||||
[
|
||||
'id' => 'complete',
|
||||
'name' => 'complete',
|
||||
'value' => 'yes',
|
||||
'checked' => old('complete', false),
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
<?= lang('Podcast.edit') ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?= form_open_multipart(route_to('podcast-edit', $podcast->id), [
|
||||
'method' => 'post',
|
||||
'class' => 'flex flex-col',
|
||||
]) ?>
|
||||
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_section(
|
||||
|
@ -22,11 +24,8 @@
|
|||
) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.image'), 'image') ?>
|
||||
<img
|
||||
src="<?= $podcast->image->thumbnail_url ?>"
|
||||
alt="<?= $podcast->title ?>"
|
||||
class="object-cover w-32 h-32"
|
||||
/>
|
||||
|
||||
<img src="<?= $podcast->image->thumbnail_url ?>" alt="<?= $podcast->title ?>" class="object-cover w-32 h-32" />
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
|
@ -34,11 +33,14 @@
|
|||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
|
||||
|
||||
<small class="mb-4 text-gray-600"><?= lang(
|
||||
'Common.forms.image_size_hint',
|
||||
) ?></small>
|
||||
'Common.forms.image_size_hint',
|
||||
) ?></small>
|
||||
|
||||
<?= form_label(lang('Podcast.form.title'), 'title') ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'title',
|
||||
'name' => 'title',
|
||||
|
@ -46,46 +48,52 @@
|
|||
'value' => old('title', $podcast->title),
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<span class="mb-4 text-sm"><?= $podcast->link ?></span>
|
||||
|
||||
<?= form_fieldset('', ['class' => 'mb-4']) ?>
|
||||
<legend><?= lang('Podcast.form.type.label') .
|
||||
hint_tooltip(lang('Podcast.form.type.hint'), 'ml-1') ?>
|
||||
</legend>
|
||||
<?= form_radio(
|
||||
['id' => 'episodic', 'name' => 'type', 'class' => 'form-radio-btn'],
|
||||
'episodic',
|
||||
old('type') ? old('type') == 'episodic' : $podcast->type == 'episodic',
|
||||
) ?>
|
||||
<label for="episodic"><?= lang('Podcast.form.type.episodic') ?></label>
|
||||
<?= form_radio(
|
||||
['id' => 'serial', 'name' => 'type', 'class' => 'form-radio-btn'],
|
||||
'serial',
|
||||
old('type') ? old('type') == 'serial' : $podcast->type == 'serial',
|
||||
) ?>
|
||||
<label for="serial"><?= lang('Podcast.form.type.serial') ?></label>
|
||||
|
||||
<legend><?= lang('Podcast.form.type.label') .
|
||||
hint_tooltip(lang('Podcast.form.type.hint'), 'ml-1') ?>
|
||||
</legend>
|
||||
<?= form_radio(
|
||||
['id' => 'episodic', 'name' => 'type', 'class' => 'form-radio-btn'],
|
||||
'episodic',
|
||||
old('type') ? old('type') == 'episodic' : $podcast->type == 'episodic',
|
||||
) ?>
|
||||
<label for="episodic"><?= lang('Podcast.form.type.episodic') ?></label>
|
||||
<?= form_radio(
|
||||
['id' => 'serial', 'name' => 'type', 'class' => 'form-radio-btn'],
|
||||
'serial',
|
||||
old('type') ? old('type') == 'serial' : $podcast->type == 'serial',
|
||||
) ?>
|
||||
<label for="serial"><?= lang('Podcast.form.type.serial') ?></label>
|
||||
<?= form_fieldset_close() ?>
|
||||
|
||||
<div class="mb-4">
|
||||
<?= form_label(lang('Podcast.form.description'), 'description') ?>
|
||||
<?= form_markdown_editor([
|
||||
<?= component(
|
||||
'Forms/MarkdownEditor',
|
||||
[
|
||||
'content' => old('description', $podcast->description_markdown, false)
|
||||
],
|
||||
[
|
||||
'id' => 'description',
|
||||
'name' => 'description',
|
||||
'required' => 'required',
|
||||
],
|
||||
old('description', $podcast->description_markdown, false)
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
|
||||
<?= form_section(
|
||||
lang('Podcast.form.classification_section_title'),
|
||||
lang('Podcast.form.classification_section_subtitle'),
|
||||
lang('Podcast.form.classification_section_title'),
|
||||
lang('Podcast.form.classification_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.language'), 'language') ?>
|
||||
|
||||
<?= form_dropdown(
|
||||
'language',
|
||||
$languageOptions,
|
||||
|
@ -101,7 +109,7 @@
|
|||
<?= form_dropdown(
|
||||
'category',
|
||||
$categoryOptions,
|
||||
[old('category', (string) $podcast->category_id)],
|
||||
[old('category', $podcast->category_id)],
|
||||
[
|
||||
'id' => 'category',
|
||||
'class' => 'form-select mb-4',
|
||||
|
@ -116,65 +124,63 @@
|
|||
'',
|
||||
true,
|
||||
) ?>
|
||||
<?= form_multiselect(
|
||||
'other_categories[]',
|
||||
$categoryOptions,
|
||||
old('other_categories', $podcast->other_categories_ids),
|
||||
[
|
||||
'id' => 'other_categories',
|
||||
'class' => 'mb-4',
|
||||
'data-max-item-count' => '2',
|
||||
],
|
||||
) ?>
|
||||
|
||||
<?= component('Forms/MultiSelect', ['options' => $categoryOptions, 'selected' => old('other_categories', $podcast->other_categories_ids)], [
|
||||
'id' => 'other_categories',
|
||||
'name' => 'other_categories[]',
|
||||
'class' => 'mb-4',
|
||||
'data-max-item-count' => '2',
|
||||
]) ?>
|
||||
|
||||
<?= form_fieldset('', ['class' => 'mb-4']) ?>
|
||||
<legend><?= lang('Podcast.form.parental_advisory.label') .
|
||||
hint_tooltip(lang('Podcast.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'
|
||||
: $podcast->parental_advisory === null,
|
||||
) ?>
|
||||
<label for="undefined"><?= lang(
|
||||
'Podcast.form.parental_advisory.undefined',
|
||||
) ?></label>
|
||||
<?= form_radio(
|
||||
[
|
||||
'id' => 'clean',
|
||||
'name' => 'parental_advisory',
|
||||
'class' => 'form-radio-btn',
|
||||
],
|
||||
'clean',
|
||||
old('parental_advisory')
|
||||
? old('parental_advisory') === 'clean'
|
||||
: $podcast->parental_advisory === 'clean',
|
||||
) ?>
|
||||
<label for="clean"><?= lang(
|
||||
'Podcast.form.parental_advisory.clean',
|
||||
) ?></label>
|
||||
<?= form_radio(
|
||||
[
|
||||
'id' => 'explicit',
|
||||
'name' => 'parental_advisory',
|
||||
'class' => 'form-radio-btn',
|
||||
],
|
||||
'explicit',
|
||||
old('parental_advisory')
|
||||
? old('parental_advisory') === 'explicit'
|
||||
: $podcast->parental_advisory === 'explicit',
|
||||
) ?>
|
||||
<label for="explicit"><?= lang(
|
||||
'Podcast.form.parental_advisory.explicit',
|
||||
) ?></label>
|
||||
<?= form_fieldset_close() ?>
|
||||
<legend><?= lang('Podcast.form.parental_advisory.label') .
|
||||
hint_tooltip(lang('Podcast.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'
|
||||
: $podcast->parental_advisory === null,
|
||||
) ?>
|
||||
|
||||
<label for="undefined"><?= lang(
|
||||
'Podcast.form.parental_advisory.undefined',
|
||||
) ?></label>
|
||||
<?= form_radio(
|
||||
[
|
||||
'id' => 'clean',
|
||||
'name' => 'parental_advisory',
|
||||
'class' => 'form-radio-btn',
|
||||
],
|
||||
'clean',
|
||||
old('parental_advisory')
|
||||
? old('parental_advisory') === 'clean'
|
||||
: $podcast->parental_advisory === 'clean',
|
||||
) ?>
|
||||
|
||||
<label for="clean"><?= lang(
|
||||
'Podcast.form.parental_advisory.clean',
|
||||
) ?></label>
|
||||
<?= form_radio(
|
||||
[
|
||||
'id' => 'explicit',
|
||||
'name' => 'parental_advisory',
|
||||
'class' => 'form-radio-btn',
|
||||
],
|
||||
'explicit',
|
||||
old('parental_advisory')
|
||||
? old('parental_advisory') === 'explicit'
|
||||
: $podcast->parental_advisory === 'explicit',
|
||||
) ?>
|
||||
|
||||
<label for="explicit"><?= lang(
|
||||
'Podcast.form.parental_advisory.explicit',
|
||||
) ?></label>
|
||||
<?= form_fieldset_close() ?>
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= form_section(
|
||||
|
@ -188,6 +194,7 @@
|
|||
[],
|
||||
lang('Podcast.form.owner_name_hint'),
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'owner_name',
|
||||
'name' => 'owner_name',
|
||||
|
@ -202,6 +209,7 @@
|
|||
[],
|
||||
lang('Podcast.form.owner_email_hint'),
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'owner_email',
|
||||
'name' => 'owner_email',
|
||||
|
@ -218,6 +226,7 @@
|
|||
lang('Podcast.form.publisher_hint'),
|
||||
true,
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'publisher',
|
||||
'name' => 'publisher',
|
||||
|
@ -226,6 +235,7 @@
|
|||
]) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.copyright'), 'copyright', [], '', true) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'copyright',
|
||||
'name' => 'copyright',
|
||||
|
@ -247,12 +257,14 @@
|
|||
lang('Podcast.form.location_name_hint'),
|
||||
true,
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'location_name',
|
||||
'name' => 'location_name',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('location_name', $podcast->location_name),
|
||||
]) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= form_section(
|
||||
|
@ -267,6 +279,7 @@
|
|||
lang('Podcast.form.payment_pointer_hint'),
|
||||
true,
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'payment_pointer',
|
||||
'name' => 'payment_pointer',
|
||||
|
@ -285,41 +298,41 @@
|
|||
true,
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'partner_id',
|
||||
'name' => 'partner_id',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_id', $podcast->partner_id),
|
||||
]) ?>
|
||||
'id' => 'partner_id',
|
||||
'name' => 'partner_id',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_id', $podcast->partner_id),
|
||||
]) ?>
|
||||
</div>
|
||||
<div class="flex flex-col flex-1">
|
||||
<?= form_label(
|
||||
lang('Podcast.form.partner_link_url'),
|
||||
'partner_link_url',
|
||||
[],
|
||||
lang('Podcast.form.partner_link_url_hint'),
|
||||
true,
|
||||
) ?>
|
||||
lang('Podcast.form.partner_link_url'),
|
||||
'partner_link_url',
|
||||
[],
|
||||
lang('Podcast.form.partner_link_url_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'partner_link_url',
|
||||
'name' => 'partner_link_url',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_link_url', $podcast->partner_link_url),
|
||||
]) ?>
|
||||
'id' => 'partner_link_url',
|
||||
'name' => 'partner_link_url',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_link_url', $podcast->partner_link_url),
|
||||
]) ?>
|
||||
</div>
|
||||
<div class="flex flex-col flex-1">
|
||||
<?= form_label(
|
||||
lang('Podcast.form.partner_image_url'),
|
||||
'partner_image_url',
|
||||
[],
|
||||
lang('Podcast.form.partner_image_url_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'partner_image_url',
|
||||
'name' => 'partner_image_url',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_image_url', $podcast->partner_image_url),
|
||||
]) ?>
|
||||
lang('Podcast.form.partner_image_url'),
|
||||
'partner_image_url',
|
||||
[],
|
||||
lang('Podcast.form.partner_image_url_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'partner_image_url',
|
||||
'name' => 'partner_image_url',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_image_url', $podcast->partner_image_url),
|
||||
]) ?>
|
||||
</div>
|
||||
</div>
|
||||
<?= form_section_close() ?>
|
||||
|
@ -328,6 +341,7 @@
|
|||
lang('Podcast.form.advanced_section_title'),
|
||||
lang('Podcast.form.advanced_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.custom_rss'),
|
||||
'custom_rss',
|
||||
|
@ -335,12 +349,17 @@
|
|||
lang('Podcast.form.custom_rss_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= xml_editor([
|
||||
'id' => 'custom_rss',
|
||||
'name' => 'custom_rss',
|
||||
'class' => 'form-textarea',
|
||||
'value' => old('custom_rss', $podcast->custom_rss_string),
|
||||
]) ?>
|
||||
|
||||
<?= component('Forms/XMLEditor',
|
||||
[
|
||||
'content' => old('custom_rss', $podcast->custom_rss_string)
|
||||
],
|
||||
[
|
||||
'id' => 'custom_rss',
|
||||
'name' => 'custom_rss',
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= form_section(
|
||||
|
@ -348,40 +367,62 @@
|
|||
lang('Podcast.form.status_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_switch(
|
||||
lang('Podcast.form.block'),
|
||||
['id' => 'block', 'name' => 'block'],
|
||||
'yes',
|
||||
old('block', $podcast->is_blocked),
|
||||
'mb-2',
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Podcast.form.lock'),
|
||||
'hint' => lang('Podcast.form.lock_hint'),
|
||||
],
|
||||
[
|
||||
'id' => 'lock',
|
||||
'name' => 'lock',
|
||||
'value' => 'yes',
|
||||
'checked' => old('complete', $podcast->is_locked),
|
||||
'class' => 'mb-2'
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_switch(
|
||||
lang('Podcast.form.complete'),
|
||||
['id' => 'complete', 'name' => 'complete'],
|
||||
'yes',
|
||||
old('complete', $podcast->is_completed),
|
||||
'mb-2',
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Podcast.form.block'),
|
||||
],
|
||||
[
|
||||
'id' => 'block',
|
||||
'name' => 'block',
|
||||
'value' => 'yes',
|
||||
'checked' => old('block', $podcast->is_blocked),
|
||||
'class' => 'mb-2'
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_switch(
|
||||
lang('Podcast.form.lock') .
|
||||
hint_tooltip(lang('Podcast.form.lock_hint'), 'ml-1'),
|
||||
['id' => 'lock', 'name' => 'lock'],
|
||||
'yes',
|
||||
old('lock', $podcast->is_locked),
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Podcast.form.complete'),
|
||||
],
|
||||
[
|
||||
'id' => 'complete',
|
||||
'name' => 'complete',
|
||||
'value' => 'yes',
|
||||
'checked' => old('complete', $podcast->is_completed),
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= button(
|
||||
lang('Podcast.form.submit_edit'),
|
||||
'',
|
||||
['variant' => 'primary'],
|
||||
['type' => 'submit', 'class' => 'self-end'],
|
||||
<?= component(
|
||||
'Button',
|
||||
[
|
||||
'label' => lang('Podcast.form.submit_edit'),
|
||||
'variant' => 'primary',
|
||||
],
|
||||
[
|
||||
'type' => 'submit',
|
||||
'class' => 'self-end'
|
||||
]
|
||||
) ?>
|
||||
|
||||
<?= form_close() ?>
|
||||
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
|
|
@ -99,10 +99,12 @@
|
|||
[],
|
||||
lang('Person.podcast_form.persons_hint'),
|
||||
) ?>
|
||||
<?= form_multiselect('persons[]', $personOptions, old('persons', []), [
|
||||
<?= component('Forms/MultiSelect', ['options' => $personOptions, 'selected' => old('persons', [])], [
|
||||
'id' => 'persons',
|
||||
'class' => 'form-select mb-4',
|
||||
'name' => 'persons[]',
|
||||
'class' => 'mb-4',
|
||||
'required' => 'required',
|
||||
'data-max-item-count' => '2',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
|
@ -112,9 +114,10 @@
|
|||
lang('Person.podcast_form.roles_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= form_multiselect('roles[]', $taxonomyOptions, old('roles', []), [
|
||||
<?= component('Forms/MultiSelect', ['options' => $taxonomyOptions, 'selected' => old('roles', [])], [
|
||||
'id' => 'roles',
|
||||
'class' => 'form-select mb-4',
|
||||
'name' => 'roles[]',
|
||||
'class' => 'mb-4',
|
||||
]) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
|
|
@ -103,34 +103,39 @@
|
|||
'type' => 'text',
|
||||
'placeholder' => lang("Platforms.description.{$platform->type}"),
|
||||
]) ?>
|
||||
<?= form_switch(
|
||||
lang('Platforms.visible'),
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Platforms.visible'),
|
||||
],
|
||||
[
|
||||
'id' => $platform->slug . '_visible',
|
||||
'name' => 'platforms[' . $platform->slug . '][visible]',
|
||||
],
|
||||
'yes',
|
||||
old(
|
||||
$platform->slug . '_visible',
|
||||
$platform->is_visible ? $platform->is_visible : false,
|
||||
),
|
||||
'text-sm mb-1',
|
||||
'value' => 'yes',
|
||||
'checked' => old(
|
||||
$platform->slug . '_visible',
|
||||
$platform->is_visible ? $platform->is_visible : false,
|
||||
),
|
||||
'class' => 'text-sm mb-1'
|
||||
]
|
||||
) ?>
|
||||
<?= form_switch(
|
||||
lang('Platforms.on_embeddable_player'),
|
||||
<?= component(
|
||||
'Forms/Toggler',
|
||||
[
|
||||
'label' => lang('Platforms.on_embeddable_player'),
|
||||
],
|
||||
[
|
||||
'id' => $platform->slug . '_on_embeddable_player',
|
||||
'name' =>
|
||||
'platforms[' . $platform->slug . '][on_embeddable_player]',
|
||||
],
|
||||
'yes',
|
||||
old(
|
||||
$platform->slug . '_on_embeddable_player',
|
||||
$platform->is_on_embeddable_player
|
||||
? $platform->is_on_embeddable_player
|
||||
: false,
|
||||
),
|
||||
'text-sm',
|
||||
'name' => 'platforms[' . $platform->slug . '][on_embeddable_player]',
|
||||
'value' => 'yes',
|
||||
'checked' => old(
|
||||
$platform->slug . '_on_embeddable_player',
|
||||
$platform->is_on_embeddable_player
|
||||
? $platform->is_on_embeddable_player
|
||||
: false,
|
||||
),
|
||||
'class' => 'text-sm'
|
||||
]
|
||||
) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_label(lang('User.form.roles'), 'roles') ?>
|
||||
<?= form_multiselect('roles[]', $roleOptions, $user->roles, [
|
||||
<?= component('Forms/MultiSelect', ['options' => $roleOptions, 'selected' => $user->roles], [
|
||||
'id' => 'roles',
|
||||
'name' => 'roles[]',
|
||||
'class' => 'mb-4',
|
||||
]) ?>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?= $this->include('podcast/_partials/comment_card_authenticated') ?>
|
||||
<?= $this->include('podcast/_partials/comment_card_authenticated') ?>
|
||||
<div class="-mt-2 overflow-hidden border-b border-l border-r post-replies rounded-b-xl">
|
||||
<?= form_open(
|
||||
route_to('comment-attempt-reply', $podcast->id, $episode->id, $comment->id),
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
'Podcast.episodes',
|
||||
) ?></a>
|
||||
</nav>
|
||||
|
||||
<section class="max-w-2xl px-6 py-8 mx-auto space-y-8">
|
||||
<?php foreach ($posts as $post): ?>
|
||||
<?php if ($post->reblog_of_id !== null): ?>
|
||||
|
|
5
ecs.php
5
ecs.php
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symplify\CodingStandard\Fixer\Naming\StandardizeHereNowDocKeywordFixer;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Option;
|
||||
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
|
||||
|
||||
|
@ -20,6 +21,10 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
|
||||
// skip specific generated files
|
||||
__DIR__ . '/app/Language/*/PersonsTaxonomy.php',
|
||||
|
||||
StandardizeHereNowDocKeywordFixer::class => [
|
||||
__DIR__ . '/app/Views/Components',
|
||||
]
|
||||
]);
|
||||
|
||||
$containerConfigurator->import(SetList::PSR_12);
|
||||
|
|
|
@ -35,3 +35,4 @@ parameters:
|
|||
- app/Helpers
|
||||
- app/Libraries/ActivityPub/Helpers
|
||||
- app/Libraries/Analytics/Helpers
|
||||
- app/Libraries/ViewComponents/Helpers
|
||||
|
|
|
@ -65,7 +65,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
],
|
||||
]);
|
||||
|
||||
// Path to phpstan with extensions, that PHPSTan in Rector uses to determine types
|
||||
// Path to phpstan with extensions, that PHPStan in Rector uses to determine types
|
||||
$parameters->set(
|
||||
Option::PHPSTAN_FOR_RECTOR_PATH,
|
||||
__DIR__ . '/phpstan.neon',
|
||||
|
|
|
@ -4,6 +4,7 @@ module.exports = {
|
|||
mode: "jit",
|
||||
purge: [
|
||||
"./app/Views/**/*.php",
|
||||
"./app/View/Components/**/*.php",
|
||||
"./app/Helpers/*.php",
|
||||
"./app/Resources/**/*.ts",
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue