mirror of
https://code.castopod.org/adaures/castopod
synced 2025-04-19 13:01:19 +00:00
feat: integrate stylized form components and update podcast edit page
This commit is contained in:
parent
23bdc6f8e3
commit
6536729546
@ -22,11 +22,12 @@ class Component implements ComponentInterface
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
helper('viewcomponents');
|
||||
|
||||
if ($attributes !== []) {
|
||||
$this->hydrate($attributes);
|
||||
}
|
||||
// overwrite default attributes if set
|
||||
|
||||
$this->attributes = array_merge($this->attributes, $attributes);
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ class ComponentRenderer
|
||||
private function renderPairedTags(string $output): string
|
||||
{
|
||||
$pattern = '/<\s*(?<name>[A-Z][A-Za-z0-9\.]*?)(?<attributes>[\s\S\=\'\"]*)>(?<slot>.*)<\/\s*\1\s*>/uUsm';
|
||||
|
||||
ini_set('pcre.backtrack_limit', '-1');
|
||||
/*
|
||||
$matches[0] = full tags matched and all of its content
|
||||
$matches[name] = pascal cased tag name
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
if (! function_exists('flatten_attributes')) {
|
||||
/**
|
||||
* Stringify attributes for use in HTML tags.
|
||||
*
|
||||
* Helper function used to convert a string, array, or object of attributes to a string.
|
||||
*
|
||||
* @param mixed $attributes string, array, object
|
||||
*/
|
||||
function flatten_attributes($attributes, bool $js = false): string
|
||||
{
|
||||
$atts = '';
|
||||
|
||||
if ($attributes === null) {
|
||||
return $atts;
|
||||
}
|
||||
|
||||
if (is_string($attributes)) {
|
||||
return ' ' . $attributes;
|
||||
}
|
||||
|
||||
$attributes = (array) $attributes;
|
||||
|
||||
foreach ($attributes as $key => $val) {
|
||||
$atts .= ($js) ? $key . '=' . esc($val, 'js') . ',' : ' ' . $key . '="' . $val . '"';
|
||||
}
|
||||
|
||||
return rtrim($atts, ',');
|
||||
}
|
||||
}
|
@ -57,12 +57,17 @@ export class XMLEditor extends LitElement {
|
||||
|
||||
static styles = css`
|
||||
.cm-wrap {
|
||||
border: 1px solid #6b7280;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
border: 3px solid #000000;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.cm-editor.cm-focused {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: 0 0 0 1px #2563eb;
|
||||
box-shadow: 0 0 0 2px #e7f9e4, 0 0 0 calc(4px) #009486;
|
||||
}
|
||||
.cm-gutters {
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
.breadcrumb {
|
||||
@apply inline-flex flex-wrap px-1 py-2 text-sm;
|
||||
@apply inline-flex flex-wrap px-1 text-sm;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
|
@ -138,8 +138,9 @@
|
||||
}
|
||||
|
||||
.choices__inner {
|
||||
@apply p-2 bg-white border border-gray-700;
|
||||
@apply p-2 bg-white border-black rounded-lg border-3;
|
||||
|
||||
box-shadow: 2px 2px 0 black;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 100%;
|
||||
@ -158,11 +159,11 @@
|
||||
}
|
||||
|
||||
.is-open .choices__inner {
|
||||
border-radius: 0;
|
||||
@apply rounded-b-none;
|
||||
}
|
||||
|
||||
.is-flipped.is-open .choices__inner {
|
||||
border-radius: 0;
|
||||
@apply rounded-t-none rounded-b-lg border-b-3;
|
||||
}
|
||||
|
||||
.choices__list {
|
||||
@ -172,9 +173,7 @@
|
||||
}
|
||||
|
||||
.choices__list--single {
|
||||
@apply pr-4;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
@apply inline-block w-full pr-4;
|
||||
}
|
||||
|
||||
[dir="rtl"] .choices__list--single {
|
||||
@ -191,7 +190,7 @@
|
||||
}
|
||||
|
||||
.choices__list--multiple .choices__item {
|
||||
@apply inline-block px-2 py-1 mb-1 mr-1 text-sm text-white align-middle bg-pine-600;
|
||||
@apply inline-block px-2 py-1 mb-1 mr-1 text-sm text-white align-middle rounded bg-pine-500;
|
||||
|
||||
word-break: break-all;
|
||||
box-sizing: border-box;
|
||||
@ -216,12 +215,11 @@
|
||||
}
|
||||
|
||||
.choices__list--dropdown {
|
||||
@apply z-50 border-2 border-black shadow-lg;
|
||||
visibility: hidden;
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #dddddd;
|
||||
top: 100%;
|
||||
margin-top: -1px;
|
||||
overflow: hidden;
|
||||
@ -234,10 +232,11 @@
|
||||
}
|
||||
|
||||
.is-open .choices__list--dropdown {
|
||||
border-color: #b7b7b7;
|
||||
@apply border-t-0 rounded-b-lg;
|
||||
}
|
||||
|
||||
.is-flipped .choices__list--dropdown {
|
||||
@apply border-b-0 rounded-t-lg rounded-b-none border-t-3;
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
margin-top: 0;
|
||||
|
@ -1,26 +1,17 @@
|
||||
@layer components {
|
||||
.form-radio-btn {
|
||||
@apply absolute opacity-0;
|
||||
@apply absolute mt-3 ml-3 border-black border-3 text-pine-500 focus:ring-2 focus:ring-pine-800;
|
||||
}
|
||||
|
||||
.form-radio-btn:focus + label {
|
||||
@apply ring;
|
||||
@apply ring ring-pine-100;
|
||||
}
|
||||
|
||||
.form-radio-btn + label {
|
||||
@apply inline-block px-2 py-1 text-sm text-black bg-white border rounded cursor-pointer;
|
||||
|
||||
&:hover {
|
||||
@apply bg-pine-100;
|
||||
}
|
||||
@apply inline-block py-2 pl-8 pr-2 text-sm font-semibold text-gray-500 bg-white border-black rounded-lg cursor-pointer border-3;
|
||||
}
|
||||
|
||||
.form-radio-btn:checked + label {
|
||||
@apply text-white bg-pine-600;
|
||||
|
||||
&::before {
|
||||
@apply mr-2 text-pine-200;
|
||||
content: "✓";
|
||||
}
|
||||
@apply text-black border-pine-500;
|
||||
}
|
||||
}
|
||||
|
@ -3,26 +3,37 @@
|
||||
@apply absolute w-0 h-0 opacity-0;
|
||||
|
||||
&:checked + .form-switch-slider {
|
||||
@apply bg-pine-600;
|
||||
@apply bg-pine-500;
|
||||
}
|
||||
|
||||
&:focus + .form-switch-slider {
|
||||
@apply ring;
|
||||
@apply ring ring-offset-2 ring-pine-500 ring-offset-pine-100;
|
||||
}
|
||||
|
||||
&:checked + .form-switch-slider::before {
|
||||
@apply transform translate-x-5;
|
||||
@apply transform translate-x-8;
|
||||
}
|
||||
|
||||
&:checked + .form-switch-slider::after {
|
||||
@apply transform translate-x-1;
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='%23ffffff'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='m10 15.172 9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z'/%3E%3C/svg%3E%0A");
|
||||
}
|
||||
}
|
||||
|
||||
.form-switch-slider {
|
||||
@apply relative inset-0 flex-shrink-0 w-10 h-5 transition duration-200 bg-gray-400 rounded-full cursor-pointer;
|
||||
@apply relative inset-0 flex-shrink-0 w-[72px] h-10 transition duration-200 bg-gray-400 border-black rounded-full cursor-pointer border-3;
|
||||
|
||||
&::before {
|
||||
@apply absolute w-4 h-4 transition duration-200 bg-white rounded-full ring-1 ring-black ring-opacity-5;
|
||||
@apply absolute z-10 w-[28px] h-[28px] transition duration-200 bg-white rounded-full ring-1 ring-black ring-opacity-5 shadow;
|
||||
content: "";
|
||||
left: 2px;
|
||||
bottom: 2px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
@apply absolute w-6 h-6 transition duration-150 transform translate-x-8 top-1 left-1;
|
||||
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='m12 10.586 4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z'/%3E%3C/svg%3E%0A");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
48
app/Views/Components/Forms/Field.php
Normal file
48
app/Views/Components/Forms/Field.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
class Field extends FormComponent
|
||||
{
|
||||
protected string $as = 'Input';
|
||||
|
||||
protected string $label = '';
|
||||
|
||||
protected ?string $helperText = null;
|
||||
|
||||
protected ?string $hintText = null;
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$helperText = $this->helperText === null ? '' : '<Forms.Helper>' . $this->helperText . '</Forms.Helper>';
|
||||
|
||||
$labelAttributes = [
|
||||
'for' => $this->id,
|
||||
'isOptional' => $this->required ? 'false' : 'true',
|
||||
];
|
||||
if ($this->hintText) {
|
||||
$labelAttributes['hint'] = $this->hintText;
|
||||
}
|
||||
$labelAttributes = stringify_attributes($labelAttributes);
|
||||
|
||||
// remove field specific attributes to inject the rest to Form Component
|
||||
$fieldComponentAttributes = $this->attributes;
|
||||
unset($fieldComponentAttributes['as']);
|
||||
unset($fieldComponentAttributes['label']);
|
||||
unset($fieldComponentAttributes['class']);
|
||||
unset($fieldComponentAttributes['helperText']);
|
||||
unset($fieldComponentAttributes['hintText']);
|
||||
|
||||
$fieldComponentAttributes = flatten_attributes($fieldComponentAttributes);
|
||||
|
||||
return <<<HTML
|
||||
<div class="flex flex-col {$this->class}">
|
||||
<Forms.Label {$labelAttributes}>{$this->label}</Forms.Label>
|
||||
<Forms.{$this->as} {$fieldComponentAttributes} class="mb-1"/>
|
||||
{$helperText}
|
||||
</div>
|
||||
HTML;
|
||||
}
|
||||
}
|
32
app/Views/Components/Forms/FormComponent.php
Normal file
32
app/Views/Components/Forms/FormComponent.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class FormComponent extends Component
|
||||
{
|
||||
protected ?string $id = null;
|
||||
|
||||
protected string $name = '';
|
||||
|
||||
protected string $value = '';
|
||||
|
||||
protected bool $required = false;
|
||||
|
||||
public function __construct($attributes)
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
|
||||
if ($this->id === null) {
|
||||
$this->id = $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
public function setRequired(string $value): void
|
||||
{
|
||||
$this->required = $value === 'true';
|
||||
}
|
||||
}
|
22
app/Views/Components/Forms/Helper.php
Normal file
22
app/Views/Components/Forms/Helper.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
class Helper extends FormComponent
|
||||
{
|
||||
/**
|
||||
* @var "default"|"error"
|
||||
*/
|
||||
protected string $type = 'default';
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$class = 'text-gray-600';
|
||||
|
||||
return <<<HTML
|
||||
<small class="{$class} {$this->class}">{$this->slot}</small>
|
||||
HTML;
|
||||
}
|
||||
}
|
37
app/Views/Components/Forms/Input.php
Normal file
37
app/Views/Components/Forms/Input.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
class Input extends FormComponent
|
||||
{
|
||||
protected string $type = 'text';
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$class = 'px-3 py-2 rounded-lg border-3 focus:ring-2 focus:ring-pine-500 focus:ring-offset-2 focus:ring-offset-pine-100 ' . $this->class;
|
||||
|
||||
if (session()->has('errors')) {
|
||||
$error = session('errors')[$this->name];
|
||||
if ($error) {
|
||||
$class .= ' border-red';
|
||||
}
|
||||
} else {
|
||||
$class .= ' border-black focus:border-black';
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'class' => $class,
|
||||
'type' => $this->type,
|
||||
];
|
||||
|
||||
if ($this->required) {
|
||||
$data['required'] = 'required';
|
||||
}
|
||||
|
||||
return form_input($data, old($this->name, $this->value));
|
||||
}
|
||||
}
|
@ -8,16 +8,9 @@ use ViewComponents\Component;
|
||||
|
||||
class Label extends Component
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $attributes = [
|
||||
'for' => '',
|
||||
'name' => '',
|
||||
'class' => '',
|
||||
];
|
||||
protected ?string $for = null;
|
||||
|
||||
protected string $hint = '';
|
||||
protected ?string $hint = null;
|
||||
|
||||
protected bool $isOptional = false;
|
||||
|
||||
@ -28,14 +21,14 @@ class Label extends Component
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$labelClass = $this->attributes['class'];
|
||||
$labelClass = 'text-sm ' . $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') : '';
|
||||
$hint = $this->hint === null ? '' : hint_tooltip($this->hint, 'ml-1');
|
||||
|
||||
return <<<HTML
|
||||
<label class="{$labelClass}" {$attributes}>{$this->slot}{$optionalText}{$hint}</label>
|
||||
|
@ -4,73 +4,68 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class MarkdownEditor extends Component
|
||||
class MarkdownEditor extends FormComponent
|
||||
{
|
||||
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']);
|
||||
}
|
||||
$editorClass = 'w-full flex flex-col bg-white border-3 border-black rounded-lg overflow-hidden focus-within:ring-2 focus-within:ring-offset-2 focus-withing:ring-offset-pine-100 focus-within:ring-pine-500 ' . $this->class;
|
||||
|
||||
$this->attributes['class'] = 'border-none outline-none focus:border-none focus:outline-none w-full h-full';
|
||||
$this->attributes['class'] = 'border-none outline-none focus:border-none focus:outline-none focus:ring-0 w-full h-full';
|
||||
$this->attributes['rows'] = 6;
|
||||
|
||||
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->slot) .
|
||||
'<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>';
|
||||
$textarea = form_textarea($this->attributes, old($this->name, $this->value, false));
|
||||
$icons = [
|
||||
'heading' => icon('heading'),
|
||||
'bold' => icon('bold'),
|
||||
'italic' => icon('italic'),
|
||||
'list-unordered' => icon('list-unordered'),
|
||||
'list-ordered' => icon('list-ordered'),
|
||||
'quote' => icon('quote'),
|
||||
'link' => icon('link'),
|
||||
'image-add' => icon('image-add'),
|
||||
'markdown' => icon(
|
||||
'markdown',
|
||||
'mr-1 text-lg text-gray-400'
|
||||
),
|
||||
];
|
||||
$translations = [
|
||||
'write' => lang('Common.forms.editor.write'),
|
||||
'preview' => lang('Common.forms.editor.preview'),
|
||||
'help' => lang('Common.forms.editor.help'),
|
||||
];
|
||||
|
||||
return <<<HTML
|
||||
<div class="{$editorClass}">
|
||||
<header class="sticky top-0 z-20 flex flex-wrap justify-between bg-white border-b border-black">
|
||||
<markdown-write-preview for="{$this->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">{$translations['write']}</button>
|
||||
<button type="button" slot="preview" class="px-2 focus:outline-none focus:ring-inset focus:ring-2 focus:ring-pine-600">{$translations['preview']}</button>
|
||||
</markdown-write-preview>
|
||||
<markdown-toolbar for=" {$this->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">{$icons['heading']}</md-header>
|
||||
<md-bold class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">{$icons['bold']}</md-bold>
|
||||
<md-italic class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">{$icons['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">{$icons['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">{$icons['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">{$icons['quote']}</md-quote>
|
||||
<md-link class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">{$icons['link']}</md-link>
|
||||
<md-image class="opacity-50 hover:opacity-100 focus:outline-none focus:ring-2 focus:opacity-100 focus:ring-pine-600">{$icons['image-add']}</md-image>
|
||||
</div>
|
||||
</markdown-toolbar>
|
||||
</header>
|
||||
<div class="relative">
|
||||
{$textarea}
|
||||
<markdown-preview for=" {$this->id} " class="absolute top-0 left-0 hidden w-full h-full p-2 overflow-y-auto prose bg-gray-50" showClass="bg-white" />
|
||||
</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">{$icons['markdown']}{$translations['help']}</a>
|
||||
</footer>
|
||||
</div>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
40
app/Views/Components/Forms/RadioButton.php
Normal file
40
app/Views/Components/Forms/RadioButton.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
/**
|
||||
* Form Checkbox Switch
|
||||
*
|
||||
* Abstracts form_label to stylize it as a switch toggle
|
||||
*/
|
||||
class RadioButton extends FormComponent
|
||||
{
|
||||
protected bool $isChecked = false;
|
||||
|
||||
public function setIsChecked(string $value): void
|
||||
{
|
||||
$this->isChecked = $value === 'true';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$radioInput = form_radio(
|
||||
[
|
||||
'id' => $this->value,
|
||||
'name' => $this->name,
|
||||
'class' => 'form-radio-btn',
|
||||
],
|
||||
$this->value,
|
||||
old($this->name) ? old($this->name) === $this->value : $this->isChecked,
|
||||
);
|
||||
|
||||
return <<<HTML
|
||||
<div>
|
||||
{$radioInput}
|
||||
<label for="{$this->value}">{$this->slot}</label>
|
||||
</div>
|
||||
HTML;
|
||||
}
|
||||
}
|
25
app/Views/Components/Forms/Section.php
Normal file
25
app/Views/Components/Forms/Section.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
class Section extends FormComponent
|
||||
{
|
||||
protected string $title = '';
|
||||
|
||||
protected ?string $subtitle = null;
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$subtitle = $this->subtitle === null ? '' : '<p class="text-sm text-gray-600 clear-left">' . $this->subtitle . '</p>';
|
||||
|
||||
return <<<HTML
|
||||
<fieldset class="w-full max-w-xl p-8 bg-white border-2 border-black rounded-xl {$this->class}">
|
||||
<Heading tagName="legend" class="float-left">{$this->title}</Heading>
|
||||
{$subtitle}
|
||||
<div class="flex flex-col gap-4 py-4 clear-left">{$this->slot}</div>
|
||||
</fieldset>
|
||||
HTML;
|
||||
}
|
||||
}
|
@ -4,28 +4,28 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components\Forms;
|
||||
|
||||
use ViewComponents\Component;
|
||||
|
||||
class MultiSelect extends Component
|
||||
class Select extends FormComponent
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $selected = [];
|
||||
protected string $selected;
|
||||
|
||||
public function setOptions(string $value): void
|
||||
{
|
||||
// dd(json_decode(html_entity_decode(html_entity_decode($value)), true));
|
||||
$this->options = json_decode(html_entity_decode($value), true);
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$defaultAttributes = [
|
||||
'data-class' => $this->attributes['class'],
|
||||
'multiple' => 'multiple',
|
||||
'data-class' => 'border-3 rounded-lg ' . $this->class,
|
||||
];
|
||||
$extra = array_merge($defaultAttributes, $this->attributes);
|
||||
|
||||
return form_dropdown($this->attributes['name'], $this->options, $this->selected, $extra);
|
||||
return form_dropdown($this->name, $this->options, $this->selected !== '' ? [$this->selected] : [], $extra);
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Views\Components;
|
||||
|
||||
use Exception;
|
||||
use ViewComponents\Component;
|
||||
|
||||
class Heading extends Component
|
||||
{
|
||||
protected string $level = '';
|
||||
protected string $tagName = 'div';
|
||||
|
||||
/**
|
||||
* @var "small"|"base"|"large"
|
||||
@ -18,21 +17,16 @@ class Heading extends Component
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
if ($this->level === '') {
|
||||
throw new Exception('level property must be set for Heading component.');
|
||||
}
|
||||
|
||||
$sizeClasses = [
|
||||
'small' => 'tracking-wide text-base',
|
||||
'base' => 'text-xl',
|
||||
'large' => 'text-3xl',
|
||||
];
|
||||
|
||||
$class = 'relative z-10 font-bold text-pine-800 font-display before:w-full before:absolute before:h-1/2 before:left-0 before:bottom-0 before:rounded-full before:bg-pine-100 before:-z-10 ' . $sizeClasses[$this->size];
|
||||
$level = $this->level;
|
||||
$class = $this->class . ' relative z-10 font-bold text-pine-800 font-display before:w-full before:absolute before:h-1/2 before:left-0 before:bottom-0 before:rounded-full before:bg-pine-100 before:-z-10 ' . $sizeClasses[$this->size];
|
||||
|
||||
return <<<HTML
|
||||
<h{$level} class="{$class}">{$this->slot}</h{$level}>
|
||||
<{$this->tagName} class="{$class}">{$this->slot}</{$this->tagName}>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
@ -33,3 +33,4 @@ parameters:
|
||||
paths:
|
||||
- app/Helpers
|
||||
- app/Common.php
|
||||
- app/Libraries/ViewComponents/Helpers
|
||||
|
@ -51,6 +51,12 @@ module.exports = {
|
||||
zIndex: {
|
||||
"-10": "-10",
|
||||
},
|
||||
borderWidth: {
|
||||
3: "3px",
|
||||
},
|
||||
ringWidth: {
|
||||
3: "3px",
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {},
|
||||
|
@ -79,21 +79,17 @@
|
||||
]) ?>
|
||||
</footer>
|
||||
</aside>
|
||||
<main class="holy-grail__main">
|
||||
<header class="bg-white">
|
||||
<div class="container flex flex-wrap items-end justify-between px-2 py-10 mx-auto md:px-12 gap-y-6 gap-x-6">
|
||||
<div class="flex flex-col">
|
||||
<?= render_breadcrumb('text-gray-800 text-xs') ?>
|
||||
<main class="relative holy-grail__main">
|
||||
<header class="flex-col py-10 bg-white">
|
||||
<div class="container mx-auto">
|
||||
<?= render_breadcrumb('text-gray-800 text-xs') ?>
|
||||
<div class="flex justify-between">
|
||||
<div class="flex flex-wrap items-center">
|
||||
<Heading level="1" size="large"><?= $this->renderSection(
|
||||
'pageTitle',
|
||||
) ?></Heading>
|
||||
<Heading tagName="h1" size="large"><?= $this->renderSection('pageTitle') ?></Heading>
|
||||
<?= $this->renderSection('headerLeft') ?>
|
||||
</div>
|
||||
<div class="flex gap-1"><?= $this->renderSection('headerRight') ?></div>
|
||||
</div>
|
||||
<div class="flex flex-wrap"><?= $this->renderSection(
|
||||
'headerRight',
|
||||
) ?></div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="container px-2 py-8 mx-auto md:px-12">
|
||||
|
@ -12,373 +12,216 @@
|
||||
<?= lang('Podcast.edit') ?>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('headerRight') ?>
|
||||
<Button variant="primary" type="submit" form="podcast-edit-form"><?= lang('Podcast.form.submit_edit') ?></Button>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?= form_open_multipart((string) route_to('podcast-edit', $podcast->id), [
|
||||
'id' => 'podcast-edit-form',
|
||||
'method' => 'post',
|
||||
'class' => 'flex flex-col',
|
||||
]) ?>
|
||||
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<?= form_section(
|
||||
lang('Podcast.form.identity_section_title'),
|
||||
lang('Podcast.form.identity_section_subtitle'),
|
||||
) ?>
|
||||
<Forms.Section
|
||||
class="mb-8"
|
||||
title="<?= lang('Podcast.form.identity_section_title') ?>"
|
||||
subtitle="<?= lang('Podcast.form.identity_section_subtitle') ?>" >
|
||||
|
||||
<?= form_label(lang('Podcast.form.image'), 'image') ?>
|
||||
<img src="<?= $podcast->image->thumbnail_url ?>" alt="<?= $podcast->title ?>" class="object-cover w-32 h-32" />
|
||||
<?= form_input([
|
||||
'id' => 'image',
|
||||
'name' => 'image',
|
||||
'class' => 'form-input',
|
||||
'type' => 'file',
|
||||
'accept' => '.jpg,.jpeg,.png',
|
||||
]) ?>
|
||||
<Forms.Field
|
||||
name="image"
|
||||
label="<?= lang('Podcast.form.image') ?>"
|
||||
helperText="<?= lang('Common.forms.image_size_hint') ?>"
|
||||
type="file"
|
||||
accept=".jpg,.jpeg,.png" />
|
||||
|
||||
<Forms.Field
|
||||
name="title"
|
||||
label="<?= lang('Podcast.form.title') ?>"
|
||||
helperText="<?= $podcast->link ?>"
|
||||
value="<?= $podcast->title ?>"
|
||||
required="true" />
|
||||
|
||||
<small class="mb-4 text-gray-600"><?= lang(
|
||||
'Common.forms.image_size_hint',
|
||||
) ?></small>
|
||||
<Forms.Field
|
||||
as="MarkdownEditor"
|
||||
name="description"
|
||||
label="<?= lang('Podcast.form.description') ?>"
|
||||
value="<?= $podcast->title ?>"
|
||||
required="true" />
|
||||
|
||||
<?= form_label(lang('Podcast.form.title'), 'title') ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'title',
|
||||
'name' => 'title',
|
||||
'class' => 'form-input mb-1',
|
||||
'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>
|
||||
<?= form_fieldset_close() ?>
|
||||
|
||||
<div class="mb-4">
|
||||
<Forms.Label for="description"><?= lang('Podcast.form.description') ?></Forms.Label>
|
||||
<Forms.MarkdownEditor id="description" name="description" required="required"><?= old('description', $podcast->description_markdown, false) ?></Forms.MarkdownEditor>
|
||||
</div>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= form_section(
|
||||
lang('Podcast.form.classification_section_title'),
|
||||
lang('Podcast.form.classification_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.language'), 'language') ?>
|
||||
|
||||
<?= form_dropdown(
|
||||
'language',
|
||||
$languageOptions,
|
||||
[old('language', $podcast->language_code)],
|
||||
[
|
||||
'id' => 'language',
|
||||
'class' => 'form-select mb-4',
|
||||
'required' => 'required',
|
||||
],
|
||||
) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.category'), 'category') ?>
|
||||
<?= form_dropdown(
|
||||
'category',
|
||||
$categoryOptions,
|
||||
[old('category', $podcast->category_id)],
|
||||
[
|
||||
'id' => 'category',
|
||||
'class' => 'form-select mb-4',
|
||||
'required' => 'required',
|
||||
],
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.other_categories'),
|
||||
'other_categories',
|
||||
[],
|
||||
'',
|
||||
true,
|
||||
) ?>
|
||||
|
||||
<Forms.MultiSelect
|
||||
id="other_categories"
|
||||
name="other_categories[]"
|
||||
class="mb-4"
|
||||
data-max-item-count="2"
|
||||
selected="<?= json_encode(old('other_categories', $podcast->other_categories_ids)) ?>"
|
||||
options="<?= htmlspecialchars(json_encode($categoryOptions)) ?>" />
|
||||
|
||||
<?= 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() ?>
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= form_section(
|
||||
lang('Podcast.form.author_section_title'),
|
||||
lang('Podcast.form.author_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.owner_name'),
|
||||
'owner_name',
|
||||
[],
|
||||
lang('Podcast.form.owner_name_hint'),
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'owner_name',
|
||||
'name' => 'owner_name',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('owner_name', $podcast->owner_name),
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.owner_email'),
|
||||
'owner_email',
|
||||
[],
|
||||
lang('Podcast.form.owner_email_hint'),
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'owner_email',
|
||||
'name' => 'owner_email',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('owner_email', $podcast->owner_email),
|
||||
'type' => 'email',
|
||||
'required' => 'required',
|
||||
]) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.publisher'),
|
||||
'publisher',
|
||||
[],
|
||||
lang('Podcast.form.publisher_hint'),
|
||||
true,
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'publisher',
|
||||
'name' => 'publisher',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('publisher', $podcast->publisher),
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.copyright'), 'copyright', [], '', true) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'copyright',
|
||||
'name' => 'copyright',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('copyright', $podcast->copyright),
|
||||
]) ?>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<?= form_section(
|
||||
lang('Podcast.form.location_section_title'),
|
||||
lang('Podcast.form.location_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.location_name'),
|
||||
'location_name',
|
||||
[],
|
||||
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(
|
||||
lang('Podcast.form.monetization_section_title'),
|
||||
lang('Podcast.form.monetization_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.payment_pointer'),
|
||||
'payment_pointer',
|
||||
[],
|
||||
lang('Podcast.form.payment_pointer_hint'),
|
||||
true,
|
||||
) ?>
|
||||
|
||||
<?= form_input([
|
||||
'id' => 'payment_pointer',
|
||||
'name' => 'payment_pointer',
|
||||
'class' => 'form-input mb-4',
|
||||
'value' => old('payment_pointer', $podcast->payment_pointer),
|
||||
]) ?>
|
||||
|
||||
<?= form_label(lang('Podcast.form.partnership')) ?>
|
||||
<div class="flex flex-col mb-4 gap-x-2 gap-y-4 md:flex-row">
|
||||
<div class="flex flex-col flex-shrink w-32">
|
||||
<?= form_label(
|
||||
lang('Podcast.form.partner_id'),
|
||||
'partner_id',
|
||||
[],
|
||||
lang('Podcast.form.partner_id_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'partner_id',
|
||||
'name' => 'partner_id',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_id', $podcast->partner_id),
|
||||
]) ?>
|
||||
<fieldset>
|
||||
<legend><?= lang('Podcast.form.type.label') .
|
||||
hint_tooltip(lang('Podcast.form.type.hint'), 'ml-1') ?></legend>
|
||||
<div class="flex gap-2">
|
||||
<Forms.RadioButton
|
||||
value="episodic"
|
||||
name="type"
|
||||
isChecked="<?= $podcast->type === 'episodic' ? 'true' : 'false' ?>" ><?= lang('Podcast.form.type.episodic') ?></Forms.RadioButton>
|
||||
<Forms.RadioButton
|
||||
value="serial"
|
||||
name="type"
|
||||
isChecked="<?= $podcast->type === 'serial' ? 'true' : 'false' ?>" ><?= lang('Podcast.form.type.serial') ?></Forms.RadioButton>
|
||||
</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,
|
||||
) ?>
|
||||
<?= form_input([
|
||||
'id' => 'partner_link_url',
|
||||
'name' => 'partner_link_url',
|
||||
'class' => 'form-input w-full',
|
||||
'value' => old('partner_link_url', $podcast->partner_link_url),
|
||||
]) ?>
|
||||
</fieldset>
|
||||
|
||||
</Forms.Section>
|
||||
|
||||
<Forms.Section
|
||||
class="mb-8"
|
||||
title="<?= lang('Podcast.form.classification_section_title') ?>"
|
||||
subtitle="<?= lang('Podcast.form.classification_section_subtitle') ?>" >
|
||||
|
||||
<Forms.Field
|
||||
as="Select"
|
||||
name="language"
|
||||
label="<?= lang('Podcast.form.language') ?>"
|
||||
selected="<?= $podcast->language_code ?>"
|
||||
required="true"
|
||||
options="<?= esc(json_encode($languageOptions)) ?>" />
|
||||
|
||||
<Forms.Field
|
||||
as="Select"
|
||||
name="category"
|
||||
label="<?= lang('Podcast.form.category') ?>"
|
||||
selected="<?= $podcast->category_id ?>"
|
||||
required="true"
|
||||
options="<?= esc(json_encode($categoryOptions)) ?>" />
|
||||
|
||||
<Forms.Field
|
||||
as="MultiSelect"
|
||||
name="other_categories[]"
|
||||
label="<?= lang('Podcast.form.other_categories') ?>"
|
||||
selected="<?= json_encode(old('other_categories', $podcast->other_categories_ids)) ?>"
|
||||
data-max-item-count="2"
|
||||
options="<?= esc(json_encode($categoryOptions)) ?>" />
|
||||
|
||||
<fieldset class="mb-4">
|
||||
<legend><?= lang('Podcast.form.parental_advisory.label') .
|
||||
hint_tooltip(lang('Podcast.form.parental_advisory.hint'), 'ml-1') ?></legend>
|
||||
<div class="flex gap-2">
|
||||
<Forms.RadioButton
|
||||
value="undefined"
|
||||
name="parental_advisory"
|
||||
isChecked="<?= $podcast->parental_advisory === null ? 'true' : 'false' ?>" ><?= lang('Podcast.form.parental_advisory.undefined') ?></Forms.RadioButton>
|
||||
<Forms.RadioButton
|
||||
value="clean"
|
||||
name="parental_advisory"
|
||||
isChecked="<?= $podcast->parental_advisory === 'clean' ? 'true' : 'false' ?>" ><?= lang('Podcast.form.parental_advisory.clean', ) ?></Forms.RadioButton>
|
||||
<Forms.RadioButton
|
||||
value="explicit"
|
||||
name="parental_advisory"
|
||||
isChecked="<?= $podcast->parental_advisory === 'explicit' ? 'true' : 'false' ?>" ><?= lang('Podcast.form.parental_advisory.explicit', ) ?></Forms.RadioButton>
|
||||
</div>
|
||||
</fieldset>
|
||||
</Forms.Section>
|
||||
|
||||
<Forms.Section
|
||||
class="mb-8"
|
||||
title="<?= lang('Podcast.form.author_section_title') ?>"
|
||||
subtitle="<?= lang('Podcast.form.author_section_subtitle') ?>" >
|
||||
|
||||
<Forms.Field
|
||||
name="owner_name"
|
||||
label="<?= lang('Podcast.form.owner_name') ?>"
|
||||
value="<?= $podcast->owner_name ?>"
|
||||
hintText="<?= lang('Podcast.form.owner_name_hint') ?>"
|
||||
required="true" />
|
||||
|
||||
<Forms.Field
|
||||
name="owner_email"
|
||||
type="email"
|
||||
label="<?= lang('Podcast.form.owner_email') ?>"
|
||||
value="<?= $podcast->owner_email ?>"
|
||||
hintText="<?= lang('Podcast.form.owner_email_hint') ?>"
|
||||
required="true" />
|
||||
|
||||
<Forms.Field
|
||||
name="publisher"
|
||||
label="<?= lang('Podcast.form.publisher') ?>"
|
||||
value="<?= $podcast->publisher ?>"
|
||||
hintText="<?= lang('Podcast.form.publisher_hint') ?>" />
|
||||
|
||||
<Forms.Field
|
||||
name="copyright"
|
||||
label="<?= lang('Podcast.form.copyright') ?>"
|
||||
value="<?= $podcast->copyright ?>" />
|
||||
|
||||
</Forms.Section>
|
||||
|
||||
<Forms.Section
|
||||
class="mb-8"
|
||||
title="<?= lang('Podcast.form.location_section_title') ?>"
|
||||
subtitle="<?= lang('Podcast.form.location_section_subtitle') ?>" >
|
||||
|
||||
<Forms.Field
|
||||
name="location_name"
|
||||
label="<?= lang('Podcast.form.location_name') ?>"
|
||||
value="<?= $podcast->location_name ?>"
|
||||
hintText="<?= lang('Podcast.form.location_name_hint') ?>" />
|
||||
|
||||
</Forms.Section>
|
||||
|
||||
<Forms.Section
|
||||
class="mb-8"
|
||||
title="<?= lang('Podcast.form.monetization_section_title') ?>"
|
||||
subtitle="<?= lang('Podcast.form.monetization_section_subtitle') ?>" >
|
||||
|
||||
<Forms.Field
|
||||
name="payment_pointer"
|
||||
label="<?= lang('Podcast.form.payment_pointer') ?>"
|
||||
value="<?= $podcast->payment_pointer ?>"
|
||||
hintText="<?= lang('Podcast.form.payment_pointer_hint') ?>" />
|
||||
|
||||
<fieldset class="flex flex-col items-start p-4 bg-gray-100 rounded">
|
||||
<Heading tagName="legend" class="float-left" size="small"><?= lang('Podcast.form.partnership') ?></Heading>
|
||||
<div class="flex flex-col w-full clear-left gap-x-2 gap-y-4 md:flex-row">
|
||||
<div class="flex flex-col flex-shrink w-32">
|
||||
<Forms.Label for="partner_id" hint="<?= lang('Podcast.form.partner_id_hint') ?>" isOptional="true"><?= lang('Podcast.form.partner_id') ?></Forms.Label>
|
||||
<Forms.Input name="partner_id" value="<?= $podcast->partner_id ?>" />
|
||||
</div>
|
||||
<div class="flex flex-col flex-1">
|
||||
<Forms.Label for="partner_link_url" hint="<?= lang('Podcast.form.partner_link_url_hint') ?>" isOptional="true"><?= lang('Podcast.form.partner_link_url') ?></Forms.Label>
|
||||
<Forms.Input name="partner_link_url" value="<?= $podcast->partner_link_url ?>" />
|
||||
</div>
|
||||
</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),
|
||||
]) ?>
|
||||
<div class="flex flex-col w-full mt-2">
|
||||
<Forms.Label for="partner_image_url" hint="<?= lang('Podcast.form.partner_image_url_hint') ?>" isOptional="true"><?= lang('Podcast.form.partner_image_url') ?></Forms.Label>
|
||||
<Forms.Input name="partner_image_url" value="<?= $podcast->partner_image_url ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<?= form_section_close() ?>
|
||||
</fieldset>
|
||||
</Forms.Section>
|
||||
|
||||
<?= form_section(
|
||||
lang('Podcast.form.advanced_section_title'),
|
||||
lang('Podcast.form.advanced_section_subtitle'),
|
||||
) ?>
|
||||
<Forms.Section
|
||||
class="mb-8"
|
||||
title="<?= lang('Podcast.form.advanced_section_title') ?>"
|
||||
subtitle="<?= lang('Podcast.form.advanced_section_subtitle') ?>" >
|
||||
|
||||
<?= form_label(
|
||||
lang('Podcast.form.custom_rss'),
|
||||
'custom_rss',
|
||||
[],
|
||||
lang('Podcast.form.custom_rss_hint'),
|
||||
true,
|
||||
) ?>
|
||||
<Forms.XMLEditor id="custom_rss" name="custom_rss"><?= old('custom_rss', $podcast->custom_rss_string, false) ?></Forms.XMLEditor>
|
||||
<Forms.Field
|
||||
as="XMLEditor"
|
||||
name="custom_rss"
|
||||
label="<?= lang('Podcast.form.custom_rss') ?>"
|
||||
value="<?= $podcast->custom_rss_string ?>"
|
||||
hintText="<?= lang('Podcast.form.custom_rss_hint') ?>" />
|
||||
|
||||
<?= form_section_close() ?>
|
||||
</Forms.Section>
|
||||
|
||||
<?= form_section(
|
||||
lang('Podcast.form.status_section_title'),
|
||||
lang('Podcast.form.status_section_subtitle'),
|
||||
) ?>
|
||||
|
||||
<Forms.Toggler class="mb-2" id="lock" name="lock" value="yes" checked="<?= old('complete', $podcast->is_locked) ?>" hint="<?= lang('Podcast.form.lock_hint') ?>">
|
||||
<?= lang('Podcast.form.lock') ?>
|
||||
</Forms.Toggler>
|
||||
<Forms.Toggler class="mb-2" id="block" name="block" value="yes" checked="<?= old('complete', $podcast->is_blocked) ?>">
|
||||
<?= lang('Podcast.form.block') ?>
|
||||
</Forms.Toggler>
|
||||
<Forms.Toggler id="complete" name="complete" value="yes" checked="<?= old('complete', $podcast->is_completed) ?>">
|
||||
<?= lang('Podcast.form.complete') ?>
|
||||
</Forms.Toggler>
|
||||
|
||||
<?= form_section_close() ?>
|
||||
|
||||
<Button variant="primary" type="submit" class="self-end">
|
||||
<?= lang('Podcast.form.submit_edit') ?>
|
||||
</Button>
|
||||
<Forms.Section
|
||||
class="mb-8"
|
||||
title="<?= lang('Podcast.form.status_section_title') ?>"
|
||||
subtitle="<?= lang('Podcast.form.status_section_subtitle') ?>" >
|
||||
<Forms.Toggler class="mb-2" id="lock" name="lock" value="yes" checked="<?= old('complete', $podcast->is_locked) ?>" hint="<?= lang('Podcast.form.lock_hint') ?>">
|
||||
<?= lang('Podcast.form.lock') ?>
|
||||
</Forms.Toggler>
|
||||
<Forms.Toggler class="mb-2" id="block" name="block" value="yes" checked="<?= old('complete', $podcast->is_blocked) ?>">
|
||||
<?= lang('Podcast.form.block') ?>
|
||||
</Forms.Toggler>
|
||||
<Forms.Toggler id="complete" name="complete" value="yes" checked="<?= old('complete', $podcast->is_completed) ?>">
|
||||
<?= lang('Podcast.form.complete') ?>
|
||||
</Forms.Toggler>
|
||||
</Forms.Section>
|
||||
|
||||
<?= form_close() ?>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<section class="flex flex-col">
|
||||
<header class="flex justify-between py-2">
|
||||
<Heading level="2"><?= lang('Podcast.latest_episodes') ?></Heading>
|
||||
<Heading tagName="h2"><?= lang('Podcast.latest_episodes') ?></Heading>
|
||||
<a href="<?= route_to(
|
||||
'episode-list',
|
||||
$podcast->id,
|
||||
|
Loading…
x
Reference in New Issue
Block a user