refactor: replace ui function components with class components + fix

soundbites js
This commit is contained in:
Yassine Doghri 2021-09-20 15:45:38 +00:00
parent 5413d09737
commit 746b518789
60 changed files with 507 additions and 1535 deletions

View File

@ -52,7 +52,7 @@ Other:
- [Kumbh Sans](https://fonts.google.com/specimen/Kumbh+Sans)
([Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL))
- [Montserrat](https://fonts.google.com/specimen/Montserrat)
- [Inter](https://fonts.google.com/specimen/Inter)
([Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL))
- [RemixIcon](https://remixicon.com/)
([Apache License 2.0](https://github.com/Remix-Design/RemixIcon/blob/master/License))

View File

@ -12,140 +12,6 @@ use App\Entities\Person;
use CodeIgniter\I18n\Time;
use CodeIgniter\View\Table;
if (! function_exists('button')) {
/**
* Button component
*
* Creates a stylized button or button like anchor tag if the URL is defined.
*
* @param array<string, string|null|bool> $customOptions button options: variant, size, iconLeft, iconRight
* @param array<string, string> $customAttributes Additional attributes
*/
function button(
string $label = '',
string $uri = '',
array $customOptions = [],
array $customAttributes = []
): string {
$defaultOptions = [
'variant' => 'default',
'size' => 'base',
'iconLeft' => null,
'iconRight' => null,
'isSquared' => false,
];
$options = array_merge($defaultOptions, $customOptions);
$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-500 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 .
' ' .
($options['isSquared']
? $squaredPaddings[$options['size']]
: $basePaddings[$options['size']]) .
' ' .
$sizeClass[$options['size']] .
' ' .
$variantClass[$options['variant']];
if (array_key_exists('class', $customAttributes)) {
$buttonClass .= ' ' . $customAttributes['class'];
unset($customAttributes['class']);
}
if ($options['iconLeft']) {
$label = icon((string) $options['iconLeft'], 'mr-2') . $label;
}
if ($options['iconRight']) {
$label .= icon((string) $options['iconRight'], 'ml-2');
}
if ($uri !== '') {
return anchor($uri, $label, array_merge([
'class' => $buttonClass,
], $customAttributes));
}
$defaultButtonAttributes = [
'type' => 'button',
];
$attributes = stringify_attributes(array_merge($defaultButtonAttributes, $customAttributes));
return <<<CODE_SAMPLE
<button class="{$buttonClass}" {$attributes}>
{$label}
</button>
CODE_SAMPLE;
}
}
// ------------------------------------------------------------------------
if (! function_exists('icon_button')) {
/**
* Icon Button component
*
* Abstracts the `button()` helper to create a stylized icon button
*
* @param string $icon The button icon
* @param string $title The button label
* @param array<string, string|null|bool> $customOptions button options: variant, size, iconLeft, iconRight
* @param array<string, string> $customAttributes Additional attributes
*/
function icon_button(
string $icon,
string $title,
string $uri = '',
array $customOptions = [],
array $customAttributes = []
): string {
$defaultOptions = [
'isSquared' => true,
];
$options = array_merge($defaultOptions, $customOptions);
$defaultAttributes = [
'title' => $title,
'data-toggle' => 'tooltip',
'data-placement' => 'bottom',
];
$attributes = array_merge($defaultAttributes, $customAttributes);
return button(icon($icon), $uri, $options, $attributes);
}
}
// ------------------------------------------------------------------------
if (! function_exists('hint_tooltip')) {
@ -296,13 +162,14 @@ if (! function_exists('publication_button')) {
break;
}
return button($label, $route, [
'variant' => $variant,
'iconLeft' => $iconLeft,
]);
return <<<CODE_SAMPLE
<Button variant="{$variant}" uri="{$route}" iconLeft="{$iconLeft}" >{$label}</Button>
CODE_SAMPLE;
}
}
// ------------------------------------------------------------------------
if (! function_exists('episode_numbering')) {
/**
* Returns relevant translated episode numbering.
@ -354,6 +221,9 @@ if (! function_exists('episode_numbering')) {
'</span>';
}
}
// ------------------------------------------------------------------------
if (! function_exists('location_link')) {
/**
* Returns link to display from location info
@ -377,7 +247,9 @@ if (! function_exists('location_link')) {
);
}
}
// ------------------------------------------------------------------------
if (! function_exists('person_list')) {
/**
* Returns list of persons images
@ -430,7 +302,9 @@ if (! function_exists('person_list')) {
return $personList . '</div>';
}
}
// ------------------------------------------------------------------------
if (! function_exists('play_episode_button')) {
/**
* Returns play episode button
@ -462,7 +336,9 @@ if (! function_exists('play_episode_button')) {
CODE_SAMPLE;
}
}
// ------------------------------------------------------------------------
if (! function_exists('audio_player')) {
/**
* Returns audio player
@ -500,7 +376,9 @@ if (! function_exists('audio_player')) {
CODE_SAMPLE;
}
}
// ------------------------------------------------------------------------
if (! function_exists('relative_time')) {
function relative_time(Time $time, string $class = ''): string
{

View File

@ -8,137 +8,6 @@ declare(strict_types=1);
* @link https://castopod.org/
*/
if (! function_exists('form_section')) {
/**
* Form section
*
* Used to produce a responsive form section with a title and subtitle. To close section, use form_section_close()
*
* @param string $title The section title
* @param string $subtitle The section subtitle
* @param array<string, string> $attributes Additional attributes
*/
function form_section(
string $title = '',
string $subtitle = '',
array $attributes = [],
string $customSubtitleClass = ''
): string {
$subtitleClass = 'text-sm text-gray-600';
if ($customSubtitleClass !== '') {
$subtitleClass = $customSubtitleClass;
}
$section =
'<div class="flex flex-wrap w-full gap-6 mb-8"' .
stringify_attributes($attributes) .
">\n";
$info =
'<div class="w-full max-w-xs"><h2 class="text-lg font-semibold">' .
$title .
'</h2><p class="' .
$subtitleClass .
'">' .
$subtitle .
'</p></div>';
return $section . $info . '<div class="flex flex-col w-full max-w-lg">';
}
}
//--------------------------------------------------------------------
if (! function_exists('form_section_close')) {
/**
* Form Section close Tag
*/
function form_section_close(string $extra = ''): string
{
return '</div></div>' . $extra;
}
}
//--------------------------------------------------------------------
if (! function_exists('form_switch')) {
/**
* Form Checkbox Switch
*
* Abstracts form_label to stylize it as a switch toggle
*
* @param mixed[] $data
* @param mixed[] $extra
*/
function form_switch(
string $label = '',
array $data = [],
string $value = '',
bool $checked = false,
string $class = '',
array $extra = []
): string {
$data['class'] = 'form-switch';
return '<label class="relative inline-flex items-center' .
' ' .
$class .
'">' .
form_checkbox($data, $value, $checked, $extra) .
'<span class="form-switch-slider"></span>' .
'<span class="ml-2">' .
$label .
'</span></label>';
}
}
//--------------------------------------------------------------------
if (! function_exists('form_label')) {
/**
* Form Label Tag
*
* @param string $text The text to appear onscreen
* @param string $id The id the label applies to
* @param array<string, string> $attributes Additional attributes
* @param string $hintText Hint text to add next to the label
* @param boolean $isOptional adds an optional text if true
*/
function form_label(
string $text = '',
string $id = '',
array $attributes = [],
string $hintText = '',
bool $isOptional = false
): string {
$label = '<label';
if ($id !== '') {
$label .= ' for="' . $id . '"';
}
if (is_array($attributes) && $attributes) {
foreach ($attributes as $key => $val) {
$label .= ' ' . $key . '="' . $val . '"';
}
}
$labelContent = $text;
if ($isOptional) {
$labelContent .=
'<small class="ml-1 lowercase">(' .
lang('Common.optional') .
')</small>';
}
if ($hintText !== '') {
$labelContent .= hint_tooltip($hintText, 'ml-1');
}
return $label . '>' . $labelContent . '</label>';
}
}
//--------------------------------------------------------------------
if (! function_exists('form_dropdown')) {

View File

@ -59,36 +59,28 @@ const Soundbites = (): void => {
if (soundbitePlayButtons) {
for (let i = 0; i < soundbitePlayButtons.length; i++) {
const soundbitePlayButton: HTMLButtonElement = soundbitePlayButtons[i];
soundbitePlayButton.addEventListener("click", () => {
playSoundbite(
audioPlayer,
Number(soundbitePlayButton.dataset.soundbiteStartTime),
Number(soundbitePlayButton.dataset.soundbiteDuration)
);
});
}
}
const inputFields: NodeListOf<HTMLInputElement> | null =
document.querySelectorAll("input[data-type='soundbite-field']");
if (inputFields) {
for (let i = 0; i < inputFields.length; i++) {
const inputField: HTMLInputElement = inputFields[i];
const soundbitePlayButton: HTMLButtonElement | null =
document.querySelector(
`button[data-type="play-soundbite"][data-soundbite-id="${inputField.dataset.soundbiteId}"]`
);
if (soundbitePlayButton) {
if (inputField.dataset.fieldType == "start-time") {
inputField.addEventListener("input", () => {
soundbitePlayButton.dataset.soundbiteStartTime = inputField.value;
});
} else if (inputField.dataset.fieldType == "duration") {
inputField.addEventListener("input", () => {
soundbitePlayButton.dataset.soundbiteDuration = inputField.value;
});
soundbitePlayButton.addEventListener("click", () => {
// get values from inputs to play soundbite
const startTime: HTMLInputElement | null | undefined =
soundbitePlayButton.parentElement?.parentElement?.querySelector(
'input[data-field-type="start_time"]'
);
const duration: HTMLInputElement | null | undefined =
soundbitePlayButton.parentElement?.parentElement?.querySelector(
'input[data-field-type="duration"]'
);
console.log(soundbitePlayButton.parentElement);
if (startTime && duration) {
playSoundbite(
audioPlayer,
parseFloat(startTime.value),
parseFloat(duration.value)
);
}
}
});
}
}
}

View File

@ -15,7 +15,7 @@
}
& .holy-grail__main {
@apply col-start-1 col-end-3 row-start-2 row-end-3;
@apply col-start-1 col-end-3 row-start-2 row-end-4;
}
& .holy-grail__footer {

View File

@ -33,7 +33,7 @@ class Alert extends Component
$attributes = stringify_attributes($this->attributes);
return <<<HTML
<div class="{$class}" role="alert" {$attributes}>{$glyph}<div>{$title}{$this->slot}</div></div>
<div class="{$class}" role="alert" {$attributes}>{$glyph}<div>{$title}<p>{$this->slot}</p></div></div>
HTML;
}
}

View File

@ -10,20 +10,25 @@ class Field extends FormComponent
protected string $label = '';
protected ?string $helperText = null;
protected ?string $helper = null;
protected ?string $hintText = null;
protected ?string $hint = null;
public function render(): string
{
$helperText = $this->helperText === null ? '' : '<Forms.Helper>' . $this->helperText . '</Forms.Helper>';
$helperText = '';
if ($this->helper !== null) {
$helperId = $this->id . 'Help';
$helperText = '<Forms.Helper id="' . $helperId . '">' . $this->helper . '</Forms.Helper>';
$this->attributes['aria-describedby'] = $helperId;
}
$labelAttributes = [
'for' => $this->id,
'isOptional' => $this->required ? 'false' : 'true',
];
if ($this->hintText) {
$labelAttributes['hint'] = $this->hintText;
if ($this->hint) {
$labelAttributes['hint'] = $this->hint;
}
$labelAttributes = stringify_attributes($labelAttributes);

View File

@ -16,7 +16,7 @@ class Helper extends FormComponent
$class = 'text-gray-600';
return <<<HTML
<small class="{$class} {$this->class}">{$this->slot}</small>
<small id="{$this->id}" class="{$class} {$this->class}">{$this->slot}</small>
HTML;
}
}

View File

@ -15,17 +15,17 @@ class Select extends FormComponent
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' => 'border-3 rounded-lg ' . $this->class,
'class' => 'focus:border-black focus:ring-2 focus:ring-pine-500 focus:ring-offset-2 focus:ring-offset-pine-100 border-3 rounded-lg border-black ' . $this->class,
'data-class' => $this->class,
];
$extra = array_merge($defaultAttributes, $this->attributes);
$extra = array_merge($this->attributes, $defaultAttributes);
return form_dropdown($this->name, $this->options, $this->selected !== '' ? [$this->selected] : [], $extra);
return form_dropdown($this->name, $this->options, old($this->name, $this->selected !== '' ? [$this->selected] : []), $extra);
}
}

View File

@ -12,10 +12,20 @@ class IconButton extends Component
public function render(): string
{
$attributes = stringify_attributes($this->attributes);
$attributes = [
'isSquared' => 'true',
'title' => $this->slot,
'data-toggle' => 'tooltip',
'data-placement' => 'bottom',
];
return <<<HTML
<Button isSquared="true" title="{$this->slot}" data-toggle="tooltip" data-placement="bottom" {$attributes}><Icon glyph="{$this->glyph}" /></Button>
HTML;
$attributes = array_merge($attributes, $this->attributes);
$attributes['slot'] = icon($this->glyph);
unset($attributes['glyph']);
$iconButton = new Button($attributes);
return $iconButton->render();
}
}

View File

@ -722,6 +722,7 @@ class EpisodeController extends BaseController
"soundbites.{$soundbite_id}.duration" => 'required|decimal|greater_than_equal_to[0]',
];
}
if (! $this->validate($rules)) {
return redirect()
->back()
@ -730,34 +731,33 @@ class EpisodeController extends BaseController
}
foreach ($soundbites as $soundbite_id => $soundbite) {
if ((int) $soundbite['start_time'] < (int) $soundbite['duration']) {
$data = [
'podcast_id' => $this->podcast->id,
'episode_id' => $this->episode->id,
'start_time' => (float) $soundbite['start_time'],
'duration' => (float) $soundbite['duration'],
'label' => $soundbite['label'],
'updated_by' => user_id(),
$data = [
'podcast_id' => $this->podcast->id,
'episode_id' => $this->episode->id,
'start_time' => (float) $soundbite['start_time'],
'duration' => (float) $soundbite['duration'],
'label' => $soundbite['label'],
'updated_by' => user_id(),
];
if ($soundbite_id === 0) {
$data += [
'created_by' => user_id(),
];
if ($soundbite_id === 0) {
$data += [
'created_by' => user_id(),
];
} else {
$data += [
'id' => $soundbite_id,
];
}
} else {
$data += [
'id' => $soundbite_id,
];
}
$soundbiteModel = new SoundbiteModel();
if (! $soundbiteModel->save($data)) {
return redirect()
->back()
->withInput()
->with('errors', $soundbiteModel->errors());
}
$soundbiteModel = new SoundbiteModel();
if (! $soundbiteModel->save($data)) {
return redirect()
->back()
->withInput()
->with('errors', $soundbiteModel->errors());
}
}
return redirect()->route('soundbites-edit', [$this->podcast->id, $this->episode->id]);
}

View File

@ -130,7 +130,7 @@ class InstallController extends Controller
session()
->setFlashdata('error', lang('Install.messages.databaseConnectError'));
return view('database_config');
return $this->databaseConfig();
}
// migrate if no user has been created

View File

@ -9,6 +9,7 @@ declare(strict_types=1);
*/
return [
'title' => 'Castopod installer',
'manual_config' => 'Manual configuration',
'manual_config_subtitle' =>
'Create a `.env` file with your settings and refresh the page to continue installation.',

View File

@ -9,6 +9,7 @@ declare(strict_types=1);
*/
return [
'title' => 'Installeur Castopod',
'manual_config' => 'Configuration manuelle',
'manual_config_subtitle' =>
'Créez un fichier `.env` qui contient tous vos paramètres puis rafraichissez la page pour continuer linstallation.',

View File

@ -9,10 +9,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(lang('Contributor.add'), route_to('contributor-add', $podcast->id), [
'variant' => 'accent',
'iconLeft' => 'add',
]) ?>
<Button uri="<?= route_to('contributor-add', $podcast->id) ?>" variant="accent" iconLeft="add"><?= lang('Contributor.add') ?></Button>
<?= $this->endSection() ?>
@ -35,36 +32,8 @@
[
'header' => lang('Common.actions'),
'cell' => function ($contributor, $podcast) {
return button(
lang('Contributor.edit'),
route_to(
'contributor-edit',
$podcast->id,
$contributor->id,
),
[
'variant' => 'info',
'size' => 'small',
],
[
'class' => 'mr-2',
],
) .
button(
lang('Contributor.remove'),
route_to(
'contributor-remove',
$podcast->id,
$contributor->id,
),
[
'variant' => 'danger',
'size' => 'small',
],
[
'class' => 'mr-2',
],
);
return '<Button uri="' . route_to('contributor-edit', $podcast->id, $contributor->id) . '" variant="info" size="small">' . lang('Contributor.edit') . '</Button>' .
'<Button uri="' . route_to('contributor-remove', $podcast->id, $contributor->id) . '" variant="danger" size="small">' . lang('Contributor.remove') . '</Button>';
},
],
],

View File

@ -22,7 +22,7 @@
<Forms.Field
name="audio_file"
label="<?= lang('Episode.form.audio_file') ?>"
hintText="<?= lang('Episode.form.audio_file_hint') ?>"
hint="<?= lang('Episode.form.audio_file_hint') ?>"
type="file"
accept=".mp3,.m4a"
required="true" />
@ -30,15 +30,15 @@
<Forms.Field
name="image"
label="<?= lang('Episode.form.image') ?>"
hintText="<?= lang('Episode.form.image_hint') ?>"
helperText="<?= lang('Common.forms.image_size_hint', ) ?>"
hint="<?= lang('Episode.form.image_hint') ?>"
helper="<?= lang('Common.forms.image_size_hint', ) ?>"
type="file"
accept=".jpg,.jpeg,.png" />
<Forms.Field
name="title"
label="<?= lang('Episode.form.title') ?>"
hintText="<?= lang('Episode.form.title_hint') ?>"
hint="<?= lang('Episode.form.title_hint') ?>"
required="true"
data-slugify="title" />
@ -120,7 +120,7 @@
as="MarkdownEditor"
name="description_footer"
label="<?= lang('Episode.form.description_footer') ?>"
hintText="<?= lang('Episode.form.description_footer_hint') ?>" />
hint="<?= lang('Episode.form.description_footer_hint') ?>" />
</Forms.Section>

View File

@ -26,22 +26,22 @@
<Forms.Field
name="audio_file"
label="<?= lang('Episode.form.audio_file') ?>"
hintText="<?= lang('Episode.form.audio_file_hint') ?>"
hint="<?= lang('Episode.form.audio_file_hint') ?>"
type="file"
accept=".mp3,.m4a" />
<Forms.Field
name="image"
label="<?= lang('Episode.form.image') ?>"
hintText="<?= lang('Episode.form.image_hint') ?>"
helperText="<?= lang('Common.forms.image_size_hint', ) ?>"
hint="<?= lang('Episode.form.image_hint') ?>"
helper="<?= lang('Common.forms.image_size_hint', ) ?>"
type="file"
accept=".jpg,.jpeg,.png" />
<Forms.Field
name="title"
label="<?= lang('Episode.form.title') ?>"
hintText="<?= lang('Episode.form.title_hint') ?>"
hint="<?= lang('Episode.form.title_hint') ?>"
value="<?= $episode->title ?>"
required="true"
data-slugify="title" />
@ -127,7 +127,7 @@
as="MarkdownEditor"
name="description_footer"
label="<?= lang('Episode.form.description_footer') ?>"
hintText="<?= lang('Episode.form.description_footer_hint') ?>"
hint="<?= lang('Episode.form.description_footer_hint') ?>"
value="<?= $podcast->episode_description_footer_markdown ?? '' ?>" />
</Forms.Section>

View File

@ -9,10 +9,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(lang('Episode.create'), route_to('episode-create', $podcast->id), [
'variant' => 'accent',
'iconLeft' => 'add',
]) ?>
<Button uri="<?= route_to('episode-create', $podcast->id) ?>" variant="accent" iconLeft="add"><?= lang('Episode.create') ?></Button>
<?= $this->endSection() ?>

View File

@ -50,19 +50,7 @@
[
'header' => lang('Common.actions'),
'cell' => function ($person): string {
return button(
lang('Person.episode_form.remove'),
route_to(
'episode-person-remove',
$person->podcast_id,
$person->episode_id,
$person->id,
),
[
'variant' => 'danger',
'size' => 'small',
],
);
return '<Button uri="' . route_to('episode-person-remove', $person->podcast_id, $person->episode_id, $person->id) . '" variant="danger" size="small">' . lang('Person.episode_form.remove') . '</Button>';
},
],
],
@ -82,7 +70,7 @@
id="persons"
name="persons[]"
label="<?= lang('Person.episode_form.persons') ?>"
hintText="<?= lang('Person.episode_form.persons_hint') ?>"
hint="<?= lang('Person.episode_form.persons_hint') ?>"
options="<?= htmlspecialchars(json_encode($personOptions)) ?>"
selected="<?= htmlspecialchars(json_encode(old('persons', []))) ?>"
required="true"
@ -93,7 +81,7 @@
id="roles"
name="roles[]"
label="<?= lang('Person.episode_form.roles') ?>"
hintText="<?= lang('Person.episode_form.roles_hint') ?>"
hint="<?= lang('Person.episode_form.roles_hint') ?>"
options="<?= htmlspecialchars(json_encode($taxonomyOptions)) ?>"
selected="<?= htmlspecialchars(json_encode(old('roles', []))) ?>"
required="true"

View File

@ -90,7 +90,7 @@
as="DatetimePicker"
name="scheduled_publication_date"
label="<?= lang('Episode.publish_form.scheduled_publication_date') ?>"
hintText="<?= lang('Episode.publish_form.scheduled_publication_date_hint') ?>"
hint="<?= lang('Episode.publish_form.scheduled_publication_date_hint') ?>"
value="<?= $episode->published_at ?>"
/>
</div>

View File

@ -94,7 +94,7 @@
as="DatetimePicker"
name="scheduled_publication_date"
label="<?= lang('Episode.publish_form.scheduled_publication_date') ?>"
hintText="<?= lang('Episode.publish_form.scheduled_publication_date_hint') ?>"
hint="<?= lang('Episode.publish_form.scheduled_publication_date_hint') ?>"
value="<?= $episode->published_at ?>"
/>
</div>

View File

@ -11,215 +11,63 @@
<?= $this->section('content') ?>
<?= form_open(
route_to('episode-soundbites-edit', $podcast->id, $episode->id),
[
'method' => 'post',
'class' => 'flex flex-col',
],
) ?>
<form action="<?= route_to('episode-soundbites-edit', $podcast->id, $episode->id) ?>" method="POST" class="flex flex-col">
<?= csrf_field() ?>
<?= form_section(
lang('Episode.soundbites_form.info_section_title'),
lang('Episode.soundbites_form.info_section_subtitle'),
) ?>
<Forms.Section
title="<?= lang('Episode.soundbites_form.info_section_title') ?>"
subtitle="<?= lang('Episode.soundbites_form.info_section_subtitle') ?>" >
<table class="w-full table-fixed">
<thead>
<tr>
<th class="w-3/12 px-1 py-2">
<?= form_label(
lang('Episode.soundbites_form.start_time'),
'start_time',
[],
lang('Episode.soundbites_form.start_time_hint'),
) ?></th>
<th class="w-3/12 px-1 py-2"><?= form_label(
lang('Episode.soundbites_form.duration'),
'duration',
[],
lang('Episode.soundbites_form.duration_hint'),
) ?></th>
<th class="w-7/12 px-1 py-2"><?= form_label(
lang('Episode.soundbites_form.label'),
'label',
[],
lang('Episode.soundbites_form.label_hint'),
true,
) ?></th>
<th class="w-1/12 px-1 py-2"></th>
</tr>
</thead>
<tbody>
<?php foreach ($episode->soundbites as $soundbite): ?>
<tr>
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => "soundbites[{$soundbite->id}][start_time]",
'name' => "soundbites[{$soundbite->id}][start_time]",
'class' => 'form-input w-full border-none text-center',
'value' => $soundbite->start_time,
'data-type' => 'soundbite-field',
'data-field-type' => 'start-time',
'data-soundbite-id' => $soundbite->id,
'required' => 'required',
],
) ?></td>
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => "soundbites[{$soundbite->id}][duration]",
'name' => "soundbites[{$soundbite->id}][duration]",
'class' => 'form-input w-full border-none text-center',
'value' => $soundbite->duration,
'data-type' => 'soundbite-field',
'data-field-type' => 'duration',
'data-soundbite-id' => $soundbite->id,
'required' => 'required',
],
) ?></td>
<td class="px-1 py-2 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'id' => "soundbites[{$soundbite->id}][label]",
'name' => "soundbites[{$soundbite->id}][label]",
'class' => 'form-input w-full border-none',
'value' => $soundbite->label,
],
) ?></td>
<td class="px-4 py-2"><?= icon_button(
'play',
lang('Episode.soundbites_form.play'),
'',
[
'variant' => 'primary',
],
[
'class' => 'mb-1 mr-1',
'data-type' => 'play-soundbite',
'data-soundbite-id' => $soundbite->id,
'data-soundbite-start-time' => $soundbite->start_time,
'data-soundbite-duration' => $soundbite->duration,
],
) ?>
<?= icon_button(
'delete-bin',
lang('Episode.soundbites_form.delete'),
route_to(
'soundbite-delete',
$podcast->id,
$episode->id,
$soundbite->id,
),
[
'variant' => 'danger',
],
[],
) ?>
</td>
</tr>
<?php endforeach; ?>
<tr>
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => 'soundbites[0][start_time]',
'name' => 'soundbites[0][start_time]',
'class' => 'form-input w-full border-none text-center',
'value' => old('start_time'),
'data-soundbite-id' => '0',
'data-type' => 'soundbite-field',
'data-field-type' => 'start-time',
],
) ?></td>
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'type' => 'number',
'min' => 0,
'max' => $episode->audio_file_duration,
'step' => 'any',
'id' => 'soundbites[0][duration]',
'name' => 'soundbites[0][duration]',
'class' => 'form-input w-full border-none text-center',
'value' => old('duration'),
'data-soundbite-id' => '0',
'data-type' => 'soundbite-field',
'data-field-type' => 'duration',
],
) ?></td>
<td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
[
'id' => 'soundbites[0][label]',
'name' => 'soundbites[0][label]',
'class' => 'form-input w-full border-none',
'value' => old('label'),
],
) ?></td>
<td class="px-4 py-2"><?= icon_button(
'play',
lang('Episode.soundbites_form.play'),
'',
[
'variant' => 'primary',
],
[
'data-type' => 'play-soundbite',
'data-soundbite-id' => 0,
'data-soundbite-start-time' => 0,
'data-soundbite-duration' => 0,
],
) ?>
</td>
</tr>
<tr><td colspan="3">
<audio controls preload="auto" class="w-full">
<source src="<?= $episode->audio_file_url ?>" type="<?= $episode->audio_file_mimetype ?>">
Your browser does not support the audio tag.
</audio>
</td><td class="px-4 py-2"><?= icon_button(
'timer',
lang('Episode.soundbites_form.bookmark'),
'',
[
'variant' => 'info',
],
[
'data-type' => 'get-soundbite',
'data-start-time-field-name' => 'soundbites[0][start_time]',
'data-duration-field-name' => 'soundbites[0][duration]',
],
) ?></td></tr>
</tbody>
</table>
<?php
$table = new \CodeIgniter\View\Table();
<?= form_section_close() ?>
$table->setHeading(
lang('Episode.soundbites_form.start_time') . hint_tooltip(lang('Episode.soundbites_form.start_time_hint')),
lang('Episode.soundbites_form.duration') . hint_tooltip(lang('Episode.soundbites_form.duration_hint')),
lang('Episode.soundbites_form.label') . hint_tooltip(lang('Episode.soundbites_form.label_hint')),
'',
''
);
<?= button(
lang('Episode.soundbites_form.submit_edit'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
foreach ($episode->soundbites as $soundbite) {
$table->addRow(
"<Forms.Input class='w-24' type='number' step='any' min='0' max='{$episode->audio_file_duration}' name='soundbites[{$soundbite->id}][start_time]' value='{$soundbite->start_time}' data-type='soundbite-field' data-field-type='start_time' required='true' />",
"<Forms.Input class='w-24' type='number' step='any' min='0' max='{$episode->audio_file_duration}' name='soundbites[{$soundbite->id}][duration]' value='{$soundbite->duration}' data-type='soundbite-field' data-field-type='duration' required='true' />",
"<Forms.Input class='flex-1' name='soundbites[{$soundbite->id}][label]' value='{$soundbite->label}' />",
"<IconButton variant='primary' glyph='play' data-type='play-soundbite' data-soundbite-id='{$soundbite->id}'>" . lang('Episode.soundbites_form.play') . '</IconButton>',
'<IconButton uri=' . route_to(
'soundbite-delete',
$podcast->id,
$episode->id,
$soundbite->id,
) . " variant='danger' glyph='delete-bin'>" . lang('Episode.soundbites_form.delete') . '</IconButton>'
);
}
<?= form_close() ?>
$table->addRow(
"<Forms.Input class='w-24' type='number' step='any' min='0' max='{$episode->audio_file_duration}' name='soundbites[0][start_time]' data-type='soundbite-field' data-field-type='start_time' />",
"<Forms.Input class='w-24' type='number' step='any' min='0' max='{$episode->audio_file_duration}' name='soundbites[0][duration]' data-type='soundbite-field' data-field-type='duration' />",
"<Forms.Input class='flex-1' name='soundbites[0][label]' />",
"<IconButton variant='primary' glyph='play' data-type='play-soundbite' data-soundbite-id='0'>" . lang('Episode.soundbites_form.play') . '</IconButton>',
);
echo $table->generate();
?>
<div class="flex items-center gap-x-2">
<audio controls preload="auto" class="flex-1 w-full">
<source src="<?= $episode->audio_file_url ?>" type="<?= $episode->audio_file_mimetype ?>">
Your browser does not support the audio tag.
</audio>
<IconButton glyph="timer" variant="info" data-type="get-soundbite" data-start-time-field-name="soundbites[0][start_time]" data-duration-field-name="soundbites[0][duration]" ><?= lang('Episode.soundbites_form.bookmark') ?></IconButton>
</div>
</Forms.Section>
<Button variant="primary" type="submit" class="self-end"><?= lang('Episode.soundbites_form.submit_edit') ?></Button>
</form>
<?= $this->endSection() ?>

View File

@ -12,7 +12,7 @@
<?= $this->section('content') ?>
<form action="<?= route_to('fediverse-attempt-block-actor') ?>" method="POST" class="flex flex-col max-w-md">
<Forms.Field name="handle" label="<?= lang('Fediverse.block_lists_form.handle') ?>" hintText="<?= lang('Fediverse.block_lists_form.handle_hint') ?>" />
<Forms.Field name="handle" label="<?= lang('Fediverse.block_lists_form.handle') ?>" hint="<?= lang('Fediverse.block_lists_form.handle_hint') ?>" />
<Button variant="primary" type="submit" class="self-end"><?= lang('Fediverse.block_lists_form.submit') ?></Button>
</form>
@ -34,21 +34,7 @@
$blockedActor->id .
'" />' .
csrf_field() .
button(
lang('Fediverse.list.unblock'),
route_to(
'fediverse-unblock-actor',
$blockedActor->username,
),
[
'variant' => 'info',
'size' => 'small',
],
[
'class' => 'mr-2',
'type' => 'submit',
],
) .
'<Button uri="' . route_to('fediverse-unblock-actor', $blockedActor->username) . '" variant="info" size="small" type="submit">' . lang('Fediverse.list.unblock') . '</Button>' .
'</form>';
},
],

View File

@ -34,21 +34,7 @@
$blockedDomain->name .
'" />' .
csrf_field() .
button(
lang('Fediverse.list.unblock'),
route_to(
'fediverse-unblock-domain',
$blockedDomain->name,
),
[
'variant' => 'info',
'size' => 'small',
],
[
'class' => 'mr-2',
'type' => 'submit',
],
) .
'<Button uri="' . route_to('fediverse-unblock-domain', $blockedDomain->name) . '" variant="info" size="small" type="submit">' . lang('Fediverse.list.unblock') . '</Button>' .
'</form>';
},
],

View File

@ -11,9 +11,6 @@
<?= $this->section('content') ?>
<?= form_open(route_to('page-create'), [
'class' => 'flex flex-col max-w-3xl',
]) ?>
<form action="<?= route_to('page-create') ?>" method="POST" class="flex flex-col max-w-3xl gap-y-4">
<?= csrf_field() ?>

View File

@ -9,10 +9,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(lang('Page.create'), route_to('page-create'), [
'variant' => 'accent',
'iconLeft' => 'add',
]) ?>
<Button uri="<?= route_to('page-create') ?>" variant="accent" iconLeft="add"><?= lang('Page.create') ?></Button>
<?= $this->endSection() ?>
@ -33,36 +30,9 @@
[
'header' => lang('Common.actions'),
'cell' => function ($page) {
return button(
lang('Page.go_to_page'),
route_to('page', $page->slug),
[
'variant' => 'secondary',
'size' => 'small',
],
[
'class' => 'mr-2',
],
) .
button(
lang('Page.edit'),
route_to('page-edit', $page->id),
[
'variant' => 'info',
'size' => 'small',
],
[
'class' => 'mr-2',
],
) .
button(
lang('Page.delete'),
route_to('page-delete', $page->id),
[
'variant' => 'danger',
'size' => 'small',
],
);
return '<Button uri="' . route_to('page', $page->slug) . '" variant="secondary" size="small">' . lang('Page.go_to_page') . '</Button>' .
'<Button uri="' . route_to('page-edit', $page->id) . '" variant="info" size="small">' . lang('Page.edit') . '</Button>' .
'<Button uri="' . route_to('page-delete', $page->id) . '" variant="danger" size="small">' . lang('Page.delete') . '</Button>';
},
],
],

View File

@ -9,10 +9,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(lang('Page.edit'), route_to('page-edit', $page->id), [
'variant' => 'accent',
'iconLeft' => 'add',
]) ?>
<Button variant="accent" uri="<?= route_to('page-edit', $page->id) ?>" iconLeft="add"><?= lang('Page.edit') ?></Button>
<?= $this->endSection() ?>
<?= $this->section('content') ?>

View File

@ -17,7 +17,7 @@
<Forms.Field
name="image"
label="<?= lang('Person.form.image') ?>"
helperText="<?= lang('Person.form.image_size_hint') ?>"
helper="<?= lang('Person.form.image_size_hint') ?>"
type="file"
required="true"
accept=".jpg,.jpeg,.png" />
@ -25,19 +25,19 @@
<Forms.Field
name="full_name"
label="<?= lang('Person.form.full_name') ?>"
hintText="<?= lang('Person.form.full_name_hint') ?>"
hint="<?= lang('Person.form.full_name_hint') ?>"
required="true"
data-slugify="title" />
<Forms.Field
name="unique_name"
label="<?= lang('Person.form.unique_name') ?>"
hintText="<?= lang('Person.form.unique_name_hint') ?>"
hint="<?= lang('Person.form.unique_name_hint') ?>"
required="true" />
<Forms.Field
name="information_url"
label="<?= lang('Person.form.information_url') ?>"
hintText="<?= lang('Person.form.information_url_hint') ?>" />
hint="<?= lang('Person.form.information_url_hint') ?>" />
<Button variant="primary" class="self-end" type="submit"><?= lang('Person.form.submit_create') ?></Button>

View File

@ -19,7 +19,7 @@
<Forms.Field
name="image"
label="<?= lang('Person.form.image') ?>"
helperText="<?= lang('Person.form.image_size_hint') ?>"
helper="<?= lang('Person.form.image_size_hint') ?>"
type="file"
accept=".jpg,.jpeg,.png" />
@ -27,7 +27,7 @@
name="full_name"
value="<?= $person->full_name ?>"
label="<?= lang('Person.form.full_name') ?>"
hintText="<?= lang('Person.form.full_name_hint') ?>"
hint="<?= lang('Person.form.full_name_hint') ?>"
required="true"
data-slugify="title" />
@ -35,12 +35,12 @@
name="unique_name"
value="<?= $person->unique_name ?>"
label="<?= lang('Person.form.unique_name') ?>"
hintText="<?= lang('Person.form.unique_name_hint') ?>"
hint="<?= lang('Person.form.unique_name_hint') ?>"
required="true" />
<Forms.Field
name="information_url"
label="<?= lang('Person.form.information_url') ?>"
hintText="<?= lang('Person.form.information_url_hint') ?>"
hint="<?= lang('Person.form.information_url_hint') ?>"
value="<?= $person->information_url ?>" />
<Button variant="primary" class="self-end" type="submit"><?= lang('Person.form.submit_edit') ?></Button>

View File

@ -9,17 +9,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(
lang('Person.create'),
route_to('person-create'),
[
'variant' => 'primary',
'iconLeft' => 'add',
],
[
'class' => 'mr-2',
],
) ?>
<Button uri="<?= route_to('person-create') ?>" variant="primary" iconLeft="add"><?= lang('Person.create') ?></Button>
<?= $this->endSection() ?>
<?= $this->section('content') ?>

View File

@ -10,17 +10,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(
lang('Person.edit'),
route_to('person-edit', $person->id),
[
'variant' => 'secondary',
'iconLeft' => 'edit',
],
[
'class' => 'mr-2',
],
) ?>
<Button uri="<?= route_to('person-edit', $person->id) ?>" variant="secondary" iconLeft="edit"><?= lang('Person.edit') ?></Button>
<?= $this->endSection() ?>
<?= $this->section('content') ?>

View File

@ -25,7 +25,7 @@
<Forms.Field
name="image"
label="<?= lang('Podcast.form.image') ?>"
helperText="<?= lang('Common.forms.image_size_hint') ?>"
helper="<?= lang('Common.forms.image_size_hint') ?>"
type="file"
required="true"
accept=".jpg,.jpeg,.png" />
@ -121,20 +121,20 @@
<Forms.Field
name="owner_name"
label="<?= lang('Podcast.form.owner_name') ?>"
hintText="<?= lang('Podcast.form.owner_name_hint') ?>"
hint="<?= lang('Podcast.form.owner_name_hint') ?>"
required="true" />
<Forms.Field
name="owner_email"
type="email"
label="<?= lang('Podcast.form.owner_email') ?>"
hintText="<?= lang('Podcast.form.owner_email_hint') ?>"
hint="<?= lang('Podcast.form.owner_email_hint') ?>"
required="true" />
<Forms.Field
name="publisher"
label="<?= lang('Podcast.form.publisher') ?>"
hintText="<?= lang('Podcast.form.publisher_hint') ?>" />
hint="<?= lang('Podcast.form.publisher_hint') ?>" />
<Forms.Field
name="copyright"
@ -150,7 +150,7 @@
<Forms.Field
name="location_name"
label="<?= lang('Podcast.form.location_name') ?>"
hintText="<?= lang('Podcast.form.location_name_hint') ?>" />
hint="<?= lang('Podcast.form.location_name_hint') ?>" />
</Forms.Section>
@ -162,7 +162,7 @@
<Forms.Field
name="payment_pointer"
label="<?= lang('Podcast.form.payment_pointer') ?>"
hintText="<?= lang('Podcast.form.payment_pointer_hint') ?>" />
hint="<?= 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>
@ -192,7 +192,7 @@
as="XMLEditor"
name="custom_rss"
label="<?= lang('Podcast.form.custom_rss') ?>"
hintText="<?= lang('Podcast.form.custom_rss_hint') ?>" />
hint="<?= lang('Podcast.form.custom_rss_hint') ?>" />
</Forms.Section>

View File

@ -29,14 +29,14 @@
<Forms.Field
name="image"
label="<?= lang('Podcast.form.image') ?>"
helperText="<?= lang('Common.forms.image_size_hint') ?>"
helper="<?= lang('Common.forms.image_size_hint') ?>"
type="file"
accept=".jpg,.jpeg,.png" />
<Forms.Field
name="title"
label="<?= lang('Podcast.form.title') ?>"
helperText="<?= $podcast->link ?>"
helper="<?= $podcast->link ?>"
value="<?= $podcast->title ?>"
required="true" />
@ -74,22 +74,22 @@
name="language"
label="<?= lang('Podcast.form.language') ?>"
selected="<?= $podcast->language_code ?>"
required="true"
options="<?= esc(json_encode($languageOptions)) ?>" />
options="<?= esc(json_encode($languageOptions)) ?>"
required="true" />
<Forms.Field
as="Select"
name="category"
label="<?= lang('Podcast.form.category') ?>"
selected="<?= $podcast->category_id ?>"
required="true"
options="<?= esc(json_encode($categoryOptions)) ?>" />
options="<?= esc(json_encode($categoryOptions)) ?>"
required="true" />
<Forms.Field
as="MultiSelect"
name="other_categories[]"
label="<?= lang('Podcast.form.other_categories') ?>"
selected="<?= json_encode(old('other_categories', $podcast->other_categories_ids)) ?>"
selected="<?= json_encode($podcast->other_categories_ids) ?>"
data-max-item-count="2"
options="<?= esc(json_encode($categoryOptions)) ?>" />
@ -122,7 +122,7 @@
name="owner_name"
label="<?= lang('Podcast.form.owner_name') ?>"
value="<?= $podcast->owner_name ?>"
hintText="<?= lang('Podcast.form.owner_name_hint') ?>"
hint="<?= lang('Podcast.form.owner_name_hint') ?>"
required="true" />
<Forms.Field
@ -130,14 +130,14 @@
type="email"
label="<?= lang('Podcast.form.owner_email') ?>"
value="<?= $podcast->owner_email ?>"
hintText="<?= lang('Podcast.form.owner_email_hint') ?>"
hint="<?= 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') ?>" />
hint="<?= lang('Podcast.form.publisher_hint') ?>" />
<Forms.Field
name="copyright"
@ -155,7 +155,7 @@
name="location_name"
label="<?= lang('Podcast.form.location_name') ?>"
value="<?= $podcast->location_name ?>"
hintText="<?= lang('Podcast.form.location_name_hint') ?>" />
hint="<?= lang('Podcast.form.location_name_hint') ?>" />
</Forms.Section>
@ -168,7 +168,7 @@
name="payment_pointer"
label="<?= lang('Podcast.form.payment_pointer') ?>"
value="<?= $podcast->payment_pointer ?>"
hintText="<?= lang('Podcast.form.payment_pointer_hint') ?>" />
hint="<?= 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>
@ -199,7 +199,7 @@
name="custom_rss"
label="<?= lang('Podcast.form.custom_rss') ?>"
value="<?= $podcast->custom_rss_string ?>"
hintText="<?= lang('Podcast.form.custom_rss_hint') ?>" />
hint="<?= lang('Podcast.form.custom_rss_hint') ?>" />
</Forms.Section>

View File

@ -22,7 +22,7 @@
<Forms.Field
name="imported_feed_url"
label="<?= lang('PodcastImport.imported_feed_url') ?>"
hintText="<?= lang('PodcastImport.imported_feed_url_hint') ?>"
hint="<?= lang('PodcastImport.imported_feed_url_hint') ?>"
placeholder="https://…"
type="url"
required="true" />
@ -81,13 +81,13 @@
name="season_number"
type="number"
label="<?= lang('PodcastImport.season_number') ?>"
hintText="<?= lang('PodcastImport.season_number_hint') ?>" />
hint="<?= lang('PodcastImport.season_number_hint') ?>" />
<Forms.Field
name="max_episodes"
type="number"
label="<?= lang('PodcastImport.max_episodes') ?>"
hintText="<?= lang('PodcastImport.max_episodes_hint') ?>" />
hint="<?= lang('PodcastImport.max_episodes_hint') ?>" />
</Forms.Section>

View File

@ -9,21 +9,8 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(
lang('Podcast.create'),
route_to('podcast-create'),
[
'variant' => 'accent',
'iconLeft' => 'add',
],
[
'class' => 'mr-2',
],
) ?>
<?= button(lang('Podcast.import'), route_to('podcast-import'), [
'variant' => 'primary',
'iconLeft' => 'download',
]) ?>
<Button uri="<?= route_to('podcast-create') ?>" variant="accent" iconLeft="add"><?= lang('Podcast.create') ?></Button>
<Button uri="<?= route_to('podcast-import') ?>" variant="primary" iconLeft="download"><?= lang('Podcast.import') ?></Button>
<?= $this->endSection() ?>

View File

@ -9,17 +9,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(
lang('Person.create'),
route_to('person-create'),
[
'variant' => 'primary',
'iconLeft' => 'add',
],
[
'class' => 'mr-2',
],
) ?>
<Button uri="<?= route_to('person-create') ?>" variant="primary" iconLeft="add"><?= lang('Person.create') ?></Button>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
@ -60,18 +50,7 @@
[
'header' => lang('Common.actions'),
'cell' => function ($person): string {
return button(
lang('Person.podcast_form.remove'),
route_to(
'podcast-person-remove',
$person->podcast_id,
$person->id,
),
[
'variant' => 'danger',
'size' => 'small',
],
);
return '<Button uri="' . route_to('podcast-person-remove', $person->podcast_id, $person->id) . '" variant="danger" size="small">' . lang('Person.podcast_form.remove') . '</Button>';
},
],
],

View File

@ -10,9 +10,7 @@
<?= $this->section('content') ?>
<?= form_open(route_to('platforms-save', $podcast->id, $platformType), [
'class' => 'flex flex-col max-w-md',
]) ?>
<form action="<?= route_to('platforms-save', $podcast->id, $platformType) ?>" method="POST" class="flex flex-col max-w-md">
<?= csrf_field() ?>
<?php foreach ($platforms as $platform): ?>
@ -106,6 +104,6 @@
<Button variant="primary" type="submit" class="self-end"><?= lang('Platforms.submit') ?></Button>
<?= form_close() ?>
</form>
<?= $this->endSection() ?>

View File

@ -9,21 +9,8 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(
lang('Podcast.edit'),
route_to('podcast-edit', $podcast->id),
[
'variant' => 'primary',
'iconLeft' => 'edit',
],
[
'class' => 'mr-2',
],
) ?>
<?= button(lang('Episode.create'), route_to('episode-create', $podcast->id), [
'variant' => 'accent',
'iconLeft' => 'add',
]) ?>
<Button uri="<?= route_to('podcast-edit', $podcast->id) ?>" variant="primary" iconLeft="edit"><?= lang('Podcast.edit') ?></Button>
<Button uri="<?= route_to('episode-create', $podcast->id) ?>" variant="accent" iconLeft="add"><?= lang('Episode.create') ?></Button>
<?= $this->endSection() ?>
<?= $this->section('content') ?>

View File

@ -11,49 +11,29 @@
<?= $this->section('content') ?>
<?= form_open(route_to('user-create'), [
'class' => 'flex flex-col max-w-sm',
]) ?>
<form action="<?= route_to('user-create') ?>" method="POST" class="flex flex-col max-w-sm">
<?= csrf_field() ?>
<?= form_label(lang('User.form.email'), 'email') ?>
<?= form_input([
'id' => 'email',
'name' => 'email',
'class' => 'form-input mb-4',
'value' => old('email'),
'type' => 'email',
]) ?>
<Forms.Field
name="email"
type="email"
label="<?= lang('User.form.email') ?>"
required="true" />
<?= form_label(lang('User.form.username'), 'username') ?>
<?= form_input([
'id' => 'username',
'name' => 'username',
'class' => 'form-input mb-4',
'value' => old('username'),
]) ?>
<Forms.Field
name="username"
label="<?= lang('User.form.username') ?>"
required="true" />
<?= form_label(lang('User.form.password'), 'password') ?>
<?= form_input([
'id' => 'password',
'name' => 'password',
'class' => 'form-input mb-4',
'type' => 'password',
'autocomplete' => 'new-password',
]) ?>
<Forms.Field
name="password"
type="password"
label="<?= lang('User.form.password') ?>"
required="true"
autocomplete="new-password" />
<?= button(
lang('User.form.submit_create'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Button variant="primary" type="submit" class="self-end"><?= lang('User.form.submit_create') ?></Button>
<?= form_close() ?>
</form>
<?= $this->endSection() ?>

View File

@ -15,26 +15,19 @@
<?= $this->section('content') ?>
<?= form_open(route_to('user-edit', $user->id), [
'class' => 'flex flex-col max-w-sm',
]) ?>
<form action="<?= route_to('user-edit', $user->id) ?>" method="POST" class="flex flex-col max-w-sm">
<?= csrf_field() ?>
<?= form_label(lang('User.form.roles'), 'roles') ?>
<Forms.MultiSelect id="roles" name="roles[]" class="mb-4" required="required" options="<?= htmlspecialchars(json_encode($roleOptions)) ?>" selected="<?= htmlspecialchars(json_encode($user->roles)) ?>"/>
<Forms.Field
id="roles"
name="roles[]"
label="<?= lang('User.form.roles') ?>"
required="true"
options="<?= esc(json_encode($roleOptions)) ?>"
selected="<?= esc(json_encode($user->roles)) ?>" />
<?= button(
lang('User.form.submit_edit'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Button variant="primary" type="submit" class="self-end"><?= lang('User.form.submit_edit') ?></Button>
<?= form_close() ?>
</form>
<?= $this->endSection() ?>

View File

@ -9,10 +9,7 @@
<?= $this->endSection() ?>
<?= $this->section('headerRight') ?>
<?= button(lang('User.create'), route_to('user-create'), [
'variant' => 'accent',
'iconLeft' => 'user-add',
]) ?>
<Button uri="<?= route_to('user-create') ?>" variant="accent" iconLeft="user-add"><?= lang('User.create') ?></Button>
<?= $this->endSection() ?>
@ -34,19 +31,9 @@
'header' => lang('User.list.roles'),
'cell' => function ($user) {
return implode(',', $user->roles) .
icon_button(
'edit',
lang('User.edit_roles', [
'username' => $user->username,
]),
route_to('user-edit', $user->id),
[
'variant' => 'info',
],
[
'class' => 'ml-2',
],
);
'<IconButton uri="' . route_to('user-edit', $user->id) . '" glyph="edit" variant="info">' . lang('User.edit_roles', [
'username' => $user->username,
]) . '</IconButton>';
},
],
[
@ -60,39 +47,9 @@
[
'header' => lang('Common.actions'),
'cell' => function ($user) {
return button(
lang('User.forcePassReset'),
route_to('user-force_pass_reset', $user->id),
[
'variant' => 'secondary',
'size' => 'small',
],
[
'class' => 'mr-2',
],
) .
button(
lang('User.' . ($user->isBanned() ? 'unban' : 'ban')),
route_to(
$user->isBanned() ? 'user-unban' : 'user-ban',
$user->id,
),
[
'variant' => 'warning',
'size' => 'small',
],
[
'class' => 'mr-2',
],
) .
button(
lang('User.delete'),
route_to('user-delete', $user->id),
[
'variant' => 'danger',
'size' => 'small',
],
);
return '<Button uri="' . route_to('user-force_pass_reset', $user->id) . '" variant="secondary" size="small">' . lang('User.forcePassReset') . '</Button>' .
'<Button uri="' . route_to($user->isBanned() ? 'user-unban' : 'user-ban', $user->id) . '" variant="warning" size="small">' . lang('User.' . ($user->isBanned() ? 'unban' : 'ban')) . '</Button>' .
'<Button uri="' . route_to('user-delete', $user->id) . '" variant="danger" size="small">' . lang('User.delete') . '</Button>';
},
],
],

View File

@ -21,8 +21,8 @@
] ?>; color: <?= $themeData['text'] ?>;">
<img src="<?= $episode->image
->thumbnail_url ?>" alt="<?= $episode->title ?>" class="flex-shrink w-36 h-36" />
<div class="flex flex-col flex-1 min-w-0 px-4 py-2 h-36">
<div class="flex items-center">
<div class="flex flex-col items-start flex-1 min-w-0 px-4 py-2 h-36">
<div class="flex items-center w-full">
<a href="<?= route_to(
'podcast-activity',
$podcast->handle,
@ -31,7 +31,7 @@
] ?>;" class="mr-2 text-xs tracking-wider uppercase truncate opacity-75 hover:opacity-100" target="_blank">
<?= $podcast->title ?>
</a>
<a href="https://castopod.org/" class="ml-auto text-3xl text-pine-700 hover:opacity-75" title="<?= lang(
<a href="https://castopod.org/" class="ml-auto text-3xl text-pine-500 hover:opacity-75" title="<?= lang(
'Common.powered_by',
[
'castopod' => 'Castopod',

View File

@ -6,13 +6,7 @@
'numberOfLikes' => $comment->likes_count,
],
) ?>"><?= icon('heart', 'text-xl mr-1 text-gray-400 group-hover:text-red-600') . $comment->likes_count ?></button>
<?= button(
lang('Comment.reply'),
route_to('comment', $podcast->handle, $comment->episode->slug, $comment->id),
[
'size' => 'small',
],
) ?>
<Button uri="<?= route_to('comment', $podcast->handle, $comment->episode->slug, $comment->id) ?>" size="small"><?= lang('Comment.reply') ?></Button>
</form>
<?php if ($comment->replies_count): ?>
<?= anchor(

View File

@ -6,13 +6,7 @@
'numberOfLikes' => $comment->likes_count,
],
) ?>"><?= icon('heart', 'text-xl mr-1 text-gray-400 group-hover:text-red-600') . $comment->likes_count ?></button>
<?= button(
lang('Comment.reply'),
route_to('post', $podcast->handle, $comment->id),
[
'size' => 'small',
],
) ?>
<Button uri="<?= route_to('post', $podcast->handle, $comment->id) ?>" size="small"><?= lang('Comment.reply') ?></Button>
</form>
<?php if ($comment->replies_count): ?>
<?= anchor(

View File

@ -6,12 +6,6 @@
'numberOfLikes' => $reply->likes_count,
],
) ?>"><?= icon('heart', 'text-xl mr-1 text-gray-400 group-hover:text-red-600') . $reply->likes_count ?></button>
<?= button(
lang('Comment.reply'),
route_to('comment', $podcast->handle, $episode->slug, $reply->id),
[
'size' => 'small',
],
) ?>
<Button uri="<?= route_to('comment', $podcast->handle, $episode->slug, $reply->id) ?>" size="small"><?= lang('Comment.reply') ?></Button>
</form>
</footer>

View File

@ -1,46 +1,21 @@
<?= $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),
[
'class' => 'bg-gray-50 flex px-6 pt-8 pb-4',
],
) ?>
<form action="<?= route_to('comment-attempt-reply', $podcast->id, $episode->id, $comment->id) ?>" method="POST" class="flex px-6 pt-8 pb-4 bg-gray-50">
<img src="<?= interact_as_actor()
->avatar_image_url ?>" alt="<?= interact_as_actor()
->display_name ?>" class="w-12 h-12 mr-4 rounded-full ring-gray-50 ring-2" />
<div class="flex flex-col flex-1">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea mb-4 w-full',
'required' => 'required',
'placeholder' => lang('Comment.form.reply_to_placeholder', [
'actorUsername' => $comment->actor->username,
]),
],
old('message', '', false),
[
'rows' => 1,
],
) ?>
<?= button(
lang('Comment.form.submit_reply'),
'',
[
'variant' => 'primary',
'size' => 'small',
],
[
'type' => 'submit',
'class' => 'self-end',
'name' => 'action',
'value' => 'reply',
],
) ?>
<Forms.Textarea
name="message"
required="true"
class="w-full mb-4"
placeholder="<?= lang('Comment.form.reply_to_placeholder', [
'actorUsername' => $comment->actor->username,
]) ?>"
rows="1" />
<Button variant="primary" size="small" type="submit" name="action" value="reply"><?= lang('Comment.form.submit_reply') ?></Button>
</div>
<?= form_close() ?>
</form>
<?php foreach ($comment->replies as $reply): ?>
<?= view('podcast/_partials/comment_reply_authenticated', [

View File

@ -1,46 +1,21 @@
<?= $this->include('podcast/_partials/post_authenticated') ?>
<div class="-mt-2 overflow-hidden border-b border-l border-r post-replies rounded-b-xl">
<?= form_open(
route_to('post-attempt-action', interact_as_actor()->username, $post->id),
[
'class' => 'bg-gray-50 flex px-6 pt-8 pb-4',
],
) ?>
<form action="<?= route_to('post-attempt-action', interact_as_actor()->username, $post->id) ?>" method="POST" class="flex px-6 pt-8 pb-4 bg-gray-50" >
<img src="<?= interact_as_actor()
->avatar_image_url ?>" alt="<?= interact_as_actor()
->display_name ?>" class="w-12 h-12 mr-4 rounded-full ring-gray-50 ring-2" />
<div class="flex flex-col flex-1">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea mb-4 w-full',
'required' => 'required',
'placeholder' => lang('Post.form.reply_to_placeholder', [
'actorUsername' => $post->actor->username,
]),
],
old('message', '', false),
[
'rows' => 1,
],
) ?>
<?= button(
lang('Post.form.submit_reply'),
'',
[
'variant' => 'primary',
'size' => 'small',
],
[
'type' => 'submit',
'class' => 'self-end',
'name' => 'action',
'value' => 'reply',
],
) ?>
<Forms.Textarea
name="message"
class="w-full mb-4"
required="true"
placeholder="<?= lang('Post.form.reply_to_placeholder', [
'actorUsername' => $post->actor->username,
]) ?>"
rows="1" />
<Button variant="primary" size="small" type="submit" name="action" value="reply" class="self-end"><?= lang('Post.form.submit_reply') ?></Button>
</div>
<?= form_close() ?>
</form>
<?php if ($post->has_replies): ?>
<?php foreach ($post->replies as $reply): ?>

View File

@ -43,9 +43,7 @@
</nav>
<section class="max-w-2xl px-6 py-8 mx-auto">
<?= form_open(route_to('post-attempt-create', interact_as_actor()->username), [
'class' => 'flex p-4 bg-white shadow rounded-xl',
]) ?>
<form action="<?= route_to('post-attempt-create', interact_as_actor()->username) ?>" method="POST" class="flex p-4 bg-white shadow rounded-xl">
<?= csrf_field() ?>
<?= view('_message_block') ?>
@ -54,59 +52,32 @@
->avatar_image_url ?>" alt="<?= interact_as_actor()
->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col flex-1 min-w-0">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea',
'required' => 'required',
'placeholder' => lang('Post.form.message_placeholder'),
],
old('message', '', false),
[
'rows' => 2,
],
) ?>
<?= form_input([
'id' => 'episode_url',
'name' => 'episode_url',
'class' => 'form-input mb-2',
'placeholder' =>
lang('Post.form.episode_url_placeholder') .
' (' .
lang('Common.optional') .
')',
'type' => 'url',
]) ?>
<?= button(
lang('Post.form.submit'),
'',
[
'variant' => 'primary',
'size' => 'small',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Forms.Textarea
name="message"
required="true"
placeholder="<?= lang('Post.form.message_placeholder') ?>"
rows="2" />
<Forms.Input
name="episode_url"
type="url"
placeholder="<?= lang('Post.form.episode_url_placeholder') . ' (' . lang('Common.optional') . ')' ?>" />
<Button variant="primary" size="small" type="submit" class="self-end mt-2"><?= lang('Post.form.submit') ?></Button>
</div>
<?= form_close() ?>
</form>
<hr class="my-4 border-2 border-pine-100">
<div class="space-y-8">
<?php foreach ($posts as $post): ?>
<?php if ($post->reblog_of_id !== null): ?>
<?= view('podcast/_partials/reblog_authenticated', [
'post' => $post->reblog_of_post,
'post' => $post->reblog_of_post,
'podcast' => $podcast,
]) ?>
]) ?>
<?php else: ?>
<?= view('podcast/_partials/post_authenticated', [
'post' => $post,
'post' => $post,
'podcast' => $podcast,
]) ?>
]) ?>
<?php endif; ?>
<?php endforeach; ?>
</div>

View File

@ -88,9 +88,7 @@
<div class="tab-panels">
<section id="comments" class="space-y-6 tab-panel">
<?= form_open(route_to('comment-attempt-create', $podcast->id, $episode->id), [
'class' => 'flex p-4',
]) ?>
<form action="<?= route_to('comment-attempt-create', $podcast->id, $episode->id) ?>" method="POST" class="flex p-4">
<?= csrf_field() ?>
<?= view('_message_block') ?>
@ -99,47 +97,23 @@
->avatar_image_url ?>" alt="<?= interact_as_actor()
->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col flex-1 min-w-0">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea mb-2',
'required' => 'required',
'placeholder' => lang(
'Comment.form.episode_message_placeholder',
),
],
old('message', '', false),
[
'rows' => 2,
],
) ?>
<?= button(
lang('Comment.form.submit'),
'',
[
'variant' => 'primary',
'size' => 'small',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Forms.Textarea
name="message"
required="true"
placeholder="<?= lang('Comment.form.episode_message_placeholder') ?>"
rows="2" />
<Button class="self-end" variant="primary" size="small" type="submit"><?= lang('Comment.form.submit') ?></Button>
</div>
<?= form_close() ?>
<?php foreach ($episode->comments as $comment): ?>
<?= view('podcast/_partials/comment_authenticated', [
'comment' => $comment,
'podcast' => $podcast,
]) ?>
<?php endforeach; ?>
</form>
<?php foreach ($episode->comments as $comment): ?>
<?= view('podcast/_partials/comment_authenticated', [
'comment' => $comment,
'podcast' => $podcast,
]) ?>
<?php endforeach; ?>
</section>
<section id="activity" class="space-y-8 tab-panel">
<?= form_open(route_to('post-attempt-create', $podcast->handle), [
'class' => 'flex p-4 bg-white shadow rounded-xl',
]) ?>
<form action="<?= route_to('post-attempt-create', $podcast->handle) ?>" method="POST" class="flex p-4 bg-white shadow rounded-xl">
<?= csrf_field() ?>
<?= view('_message_block') ?>
@ -148,41 +122,15 @@
->avatar_image_url ?>" alt="<?= interact_as_actor()
->display_name ?>" class="w-12 h-12 mr-4 rounded-full" />
<div class="flex flex-col flex-1 min-w-0">
<?= form_textarea(
[
'id' => 'message',
'name' => 'message',
'class' => 'form-textarea mb-2',
'required' => 'required',
'placeholder' => lang(
'Post.form.episode_message_placeholder',
),
],
old('message', '', false),
[
'rows' => 2,
],
) ?>
<?= form_input([
'id' => 'episode_url',
'name' => 'episode_url',
'value' => $episode->link,
'type' => 'hidden',
]) ?>
<?= button(
lang('Post.form.submit'),
'',
[
'variant' => 'primary',
'size' => 'small',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<input name="episode_url" value="<?= $episode->link ?>" type="hidden" />
<Forms.Textarea
name="message"
placeholder="<?= lang('Post.form.episode_message_placeholder') ?>"
required="true"
rows="2" />
<Button variant="primary" size="small" type="submit" class="self-end"><?= lang('Post.form.submit') ?></Button>
</div>
<?= form_close() ?>
</form>
<hr class="my-4 border border-pine-100">
<?php foreach ($episode->posts as $post): ?>
<?= view('podcast/_partials/post_authenticated', [

View File

@ -48,39 +48,18 @@
</header>
<main class="w-full max-w-md px-4 mx-auto">
<?= form_open(route_to('attempt-follow', $actor->username), [
'method' => 'post',
'class' => 'flex flex-col',
]) ?>
<form action="<?= route_to('attempt-follow', $actor->username) ?>" method="POST" class="flex flex-col">
<?= csrf_field() ?>
<?= view('_message_block') ?>
<?= form_label(
lang('Fediverse.your_handle'),
'handle',
[],
lang('Fediverse.your_handle_hint'),
) ?>
<?= form_input([
'id' => 'handle',
'name' => 'handle',
'class' => 'form-input mb-4',
'required' => 'required',
'type' => 'text',
]) ?>
<?= button(
lang('Fediverse.follow.submit'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<?= form_close() ?>
<Forms.Field
name="handle"
label="<?= lang('Fediverse.your_handle') ?>"
hint="<?= lang('Fediverse.your_handle_hint') ?>"
required="true"
/>
<Button variant="primary" type="submit" class="self-end"><?= lang('Fediverse.follow.submit') ?></Button>
</form>
</main>
<footer

View File

@ -40,41 +40,17 @@
<main class="flex-1 max-w-xl px-4 pb-8 mx-auto -mt-24">
<?= $this->include('podcast/_partials/post') ?>
<?= form_open(
route_to('post-attempt-remote-action', $post->id, $action),
[
'method' => 'post',
'class' => 'flex flex-col mt-8',
],
) ?>
<?= csrf_field() ?>
<?= view('_message_block') ?>
<form action="<?= route_to('post-attempt-remote-action', $post->id, $action) ?>" method="POST" class="flex flex-col mt-8">
<?= csrf_field() ?>
<?= view('_message_block') ?>
<?= form_label(
lang('Fediverse.your_handle'),
'handle',
[],
lang('Fediverse.your_handle_hint'),
) ?>
<?= form_input([
'id' => 'handle',
'name' => 'handle',
'class' => 'form-input mb-4',
'required' => 'required',
'type' => 'text',
]) ?>
<Forms.Field
name="handle"
label="<?= lang('Fediverse.your_handle') ?>"
hint="<?= lang('Fediverse.your_handle_hint') ?>"
required="true" />
<?= button(
lang('Fediverse.' . $action . '.submit'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<?= form_close() ?>
<Button variant="primary" type="submit" class="self-end"><?= lang('Fediverse.' . $action . '.submit') ?></Button>
</form>
</main>
</body>

View File

@ -10,32 +10,15 @@
<p class="mb-4 text-gray-600"><?= lang('Auth.enterEmailForInstructions') ?></p>
<?= form_open(route_to('forgot'), [
'class' => 'flex flex-col',
]) ?>
<?= csrf_field() ?>
<form action="<?= route_to('forgot') ?>" method="POST" class="flex flex-col">
<?= csrf_field() ?>
<?= form_label(lang('Auth.emailAddress'), 'email') ?>
<?= form_input([
'id' => 'email',
'name' => 'email',
'class' => 'form-input mb-4',
'type' => 'email',
'required' => 'required',
]) ?>
<?= button(
lang('Auth.sendInstructions'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<?= form_close() ?>
<Forms.Field
name="email"
label="<?= lang('Auth.emailAddress') ?>"
type="email"
required="true" />
<Button variant="primary" type="submit" class="self-end"><?= lang('Auth.sendInstructions') ?></Button>
</form>
<?= $this->endSection() ?>

View File

@ -8,42 +8,22 @@
<?= $this->section('content') ?>
<?= form_open(route_to('login'), [
'class' => 'flex flex-col',
]) ?>
<?= csrf_field() ?>
<form actions="<?= route_to('login') ?>" method="POST" class="flex flex-col">
<?= csrf_field() ?>
<?= form_label(lang('Auth.emailOrUsername'), 'login') ?>
<?= form_input([
'id' => 'login',
'name' => 'login',
'class' => 'form-input mb-4',
'required' => 'required',
]) ?>
<Forms.Field
name="login"
label="<?= lang('Auth.emailOrUsername') ?>"
required="true" />
<?= form_label(lang('Auth.password'), 'password') ?>
<?= form_input([
'id' => 'password',
'name' => 'password',
'class' => 'form-input mb-4',
'type' => 'password',
'required' => 'required',
]) ?>
<Forms.Field
name="password"
label="<?= lang('Auth.password') ?>"
type="password"
required="true" />
<?= button(
lang('Auth.loginAction'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<?= form_close() ?>
<Button variant="primary" type="submit" class="self-end"><?= lang('Auth.loginAction') ?></Button>
</form>
<?= $this->endSection() ?>

View File

@ -8,57 +8,30 @@
<?= $this->section('content') ?>
<?= form_open(route_to('register'), [
'class' => 'flex flex-col',
]) ?>
<form action="<?= route_to('register') ?>" method="POST" class="flex flex-col">
<?= csrf_field() ?>
<?= form_label(lang('Auth.email'), 'email') ?>
<?= form_input([
'id' => 'email',
'name' => 'email',
'class' => 'form-input',
'value' => old('email'),
'type' => 'email',
'required' => 'required',
'aria-describedby' => 'emailHelp',
]) ?>
<small id="emailHelp" class="mb-4 text-gray-700">
<?= lang('Auth.weNeverShare') ?>
</small>
<Forms.Field
name="email"
label="<?= lang('Auth.email') ?>"
helper="<?= lang('Auth.weNeverShare') ?>"
type="email"
required="true" />
<?= form_label(lang('Auth.username'), 'username') ?>
<?= form_input([
'id' => 'username',
'name' => 'username',
'class' => 'form-input mb-4',
'value' => old('username'),
'required' => 'required',
]) ?>
<Forms.Field
name="username"
label="<?= lang('Auth.username') ?>"
required="true" />
<?= form_label(lang('Auth.password'), 'password') ?>
<?= form_input([
'id' => 'password',
'name' => 'password',
'class' => 'form-input mb-4',
'type' => 'password',
'required' => 'required',
'autocomplete' => 'new-password',
]) ?>
<Forms.Field
name="password"
label="<?= lang('Auth.password') ?>"
required="true"
autocomplete="new-password" />
<?= button(
lang('Auth.register'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Button variant="primary" type="submit" class="self-end"><?= lang('Auth.register') ?></Button>
<?= form_close() ?>
</form>
<?= $this->endSection() ?>

View File

@ -10,52 +10,30 @@
<p class="mb-4"><?= lang('Auth.enterCodeEmailPassword') ?></p>
<?= form_open(route_to('reset-password'), [
'class' => 'flex flex-col',
]) ?>
<form action="<?= route_to('reset-password') ?>" method="POST" class="flex flex-col">
<?= csrf_field() ?>
<?= form_label(lang('Auth.token'), 'token') ?>
<?= form_input([
'id' => 'token',
'name' => 'token',
'class' => 'form-input mb-4',
'value' => old('token', $token ?? ''),
'required' => 'required',
]) ?>
<Forms.Field
name="token"
label="<?= lang('Auth.token') ?>"
value="<?= $token ?? '' ?>"
required="true" />
<Forms.Field
name="email"
label="<?= lang('Auth.email') ?>"
type="email"
required="true" />
<?= form_label(lang('Auth.email'), 'email') ?>
<?= form_input([
'id' => 'email',
'name' => 'email',
'class' => 'form-input mb-4',
'value' => old('email'),
'required' => 'required',
'type' => 'email',
]) ?>
<Forms.Field
name="password"
label="<?= lang('Auth.newPassword') ?>"
type="password"
required="true"
autocomplete="new-password" />
<?= form_label(lang('Auth.newPassword'), 'password') ?>
<?= form_input([
'id' => 'password',
'name' => 'password',
'class' => 'form-input mb-4',
'type' => 'password',
'required' => 'required',
'autocomplete' => 'new-password',
]) ?>
<Button variant="primary" type="submit" class="self-end"><?= lang('Auth.resetPassword') ?></Button>
<?= button(
lang('Auth.resetPassword'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<?= form_close() ?>
</form>
<?= $this->endSection() ?>

View File

@ -16,7 +16,7 @@
<body class="flex flex-col min-h-screen mx-auto">
<header class="border-b">
<div class="container flex items-center justify-between px-2 py-4 mx-auto">
Castopod installer
<?= lang('Install.title') ?>
</div>
</header>
<main class="container flex flex-col items-center justify-center flex-1 px-4 py-10 mx-auto">

View File

@ -2,48 +2,33 @@
<?= $this->section('content') ?>
<?= form_open(route_to('cache-config'), [
'class' => 'flex flex-col max-w-sm w-full',
]) ?>
<form action="<?= route_to('cache-config') ?>" method="POST" class="flex flex-col w-full max-w-sm gap-y-4">
<?= csrf_field() ?>
<h1 class="mb-4 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">3/4</span><?= lang(
'Install.form.cache_config',
) ?></h1>
<div class="flex flex-col mb-2">
<div class="flex items-center">
<span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">3/4</span>
<Heading tagName="h1"><?= lang('Install.form.cache_config') ?></h1>
</div>
<p class="mb-4 text-sm text-gray-600"><?= lang(
<p class="mt-2 text-sm text-gray-600"><?= lang(
'Install.form.cache_config_hint',
) ?></p>
</div>
<?= form_label(lang('Install.form.cache_handler'), 'db_prefix') ?>
<?= form_dropdown(
'cache_handler',
[
<Forms.Field
as="Select"
name="cache_handler"
label="<?= lang('Install.form.cache_handler') ?>"
options="<?= esc(json_encode([
'file' => lang('Install.form.cacheHandlerOptions.file'),
'redis' => lang('Install.form.cacheHandlerOptions.redis'),
'predis' => lang('Install.form.cacheHandlerOptions.predis'),
],
[old('cache_handler', 'file')],
[
'id' => 'cache_handler',
'name' => 'cache_handler',
'class' => 'form-select mb-6',
'value' => config('Database')
->default['DBPrefix'],
],
) ?>
])) ?>"
selected="file"
required="true" />
<?= button(
lang('Install.form.next') . icon('arrow-right', 'ml-2'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Button variant="primary" class="self-end" iconRight="arrow-right" type="submit"><?= lang('Install.form.next') ?></Button>
<?= form_close() ?>

View File

@ -2,56 +2,34 @@
<?= $this->section('content') ?>
<?= form_open(route_to('create-superadmin'), [
'class' => 'flex flex-col max-w-sm w-full',
]) ?>
<form action="<?= route_to('create-superadmin') ?>" method="POST" class="flex flex-col w-full max-w-sm gap-y-4">
<?= csrf_field() ?>
<h1 class="mb-4 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">4/4</span><?= lang(
'Install.form.create_superadmin',
) ?></h1>
<div class="flex items-center mb-2">
<span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">4/4</span>
<Heading tagName="h1"><?= lang('Install.form.create_superadmin') ?></Heading>
</div>
<?= form_label(lang('Install.form.email'), 'email') ?>
<?= form_input([
'id' => 'email',
'name' => 'email',
'class' => 'form-input mb-4',
'type' => 'email',
'required' => 'required',
'value' => old('email'),
]) ?>
<Forms.Field
name="email"
label="<?= lang('Install.form.email') ?>"
type="email"
required="true" />
<?= form_label(lang('Install.form.username'), 'username') ?>
<?= form_input([
'id' => 'username',
'name' => 'username',
'class' => 'form-input mb-4',
'required' => 'required',
'value' => old('username'),
]) ?>
<Forms.Field
name="username"
label="<?= lang('Install.form.username') ?>"
required="true" />
<?= form_label(lang('Install.form.password'), 'password') ?>
<?= form_input([
'id' => 'password',
'name' => 'password',
'class' => 'form-input mb-4',
'type' => 'password',
'required' => 'required',
'autocomplete' => 'new-password',
]) ?>
<Forms.Field
name="password"
label="<?= lang('Install.form.password') ?>"
type="password"
required="true"
autocomplete="new-password" />
<?= button(
icon('check', 'mr-2') . lang('Install.form.submit'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Button variant="primary" type="submit" class="self-end" iconLeft="check"><?= lang('Install.form.submit') ?></Button>
<?= form_close() ?>
</form>
<?= $this->endSection() ?>

View File

@ -2,84 +2,58 @@
<?= $this->section('content') ?>
<?= form_open(route_to('database-config'), [
'class' => 'flex flex-col max-w-sm w-full',
'autocomplete' => 'off',
]) ?>
<form action="<?= route_to('database-config') ?>" method="POST" class="flex flex-col w-full max-w-sm gap-y-4" autocomplete="off">
<?= csrf_field() ?>
<h1 class="mb-2 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">2/4</span><?= lang(
<div class="flex flex-col mb-2">
<div class="flex items-center">
<span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">2/4</span>
<Heading tagName="h1"><?= lang(
'Install.form.database_config',
) ?></h1>
) ?></Heading>
</div>
<p class="mb-4 text-sm text-gray-600"><?= lang(
<p class="mt-2 text-sm text-gray-600"><?= lang(
'Install.form.database_config_hint',
) ?></p>
</div>
<?= form_label(lang('Install.form.db_hostname'), 'db_hostname') ?>
<?= form_input([
'id' => 'db_hostname',
'name' => 'db_hostname',
'class' => 'form-input mb-4',
'value' => old('db_hostname', config('Database')->default['hostname']),
'required' => 'required',
]) ?>
<Forms.Field
name="db_hostname"
label="<?= lang('Install.form.db_hostname') ?>"
value="<?= config('Database')
->default['hostname'] ?>"
required="true" />
<?= form_label(lang('Install.form.db_name'), 'db_name') ?>
<?= form_input([
'id' => 'db_name',
'name' => 'db_name',
'class' => 'form-input mb-4',
'value' => old('db_name', config('Database')->default['database']),
'required' => 'required',
]) ?>
<Forms.Field
name="db_name"
label="<?= lang('Install.form.db_name') ?>"
value="<?= config('Database')->default['database'] ?>"
required="true" />
<?= form_label(lang('Install.form.db_username'), 'db_username') ?>
<?= form_input([
'id' => 'db_username',
'name' => 'db_username',
'class' => 'form-input mb-4',
'value' => old('db_username', config('Database')->default['username']),
'required' => 'required',
'autocomplete' => 'off',
]) ?>
<Forms.Field
name="db_username"
label="<?= lang('Install.form.db_username') ?>"
value="<?= config('Database')->default['username'] ?>"
required="true"
autocomplete="off" />
<?= form_label(lang('Install.form.db_password'), 'db_password') ?>
<?= form_input([
'id' => 'db_password',
'name' => 'db_password',
'class' => 'form-input mb-4',
'value' => old('db_password', config('Database')->default['password']),
'type' => 'password',
'required' => 'required',
'autocomplete' => 'off',
]) ?>
<Forms.Field
name="db_password"
label="<?= lang('Install.form.db_password') ?>"
value="<?= config('Database')->default['password'] ?>"
type="password"
required="true"
autocomplete="off" />
<?= form_label(
lang('Install.form.db_prefix'),
'db_prefix',
[],
lang('Install.form.db_prefix_hint'),
) ?>
<?= form_input([
'id' => 'db_prefix',
'name' => 'db_prefix',
'class' => 'form-input mb-6',
'value' => old('db_prefix', config('Database')->default['DBPrefix']),
]) ?>
<Forms.Field
name="db_prefix"
label="<?= lang('Install.form.db_prefix') ?>"
hint="<?= lang('Install.form.db_prefix_hint') ?>"
value="<?= config('Database')->default['DBPrefix'] ?>" />
<?= button(
lang('Install.form.next') . icon('arrow-right', 'ml-2'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<Button variant="primary" type="submit" class="self-end" iconRight="arrow-right"><?= lang('Install.form.next') ?></Button>
<?= form_close() ?>
</form>
<?= $this->endSection() ?>

View File

@ -1,84 +1,44 @@
<?= $this->extend('_layout') ?>
<?= $this->section('content') ?>
adz
<form action="<?= '/' .
config('Install')
->gateway .
'/instance-config' ?>" class="flex flex-col w-full max-w-sm" method="post" accept-charset="utf-8">
<form action="<?= '/' . config('Install')->gateway . '/instance-config' ?>" class="flex flex-col w-full max-w-sm gap-y-4" method="post" accept-charset="utf-8">
<?= csrf_field() ?>
<h1 class="mb-4 text-xl font-bold font-display"><span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">1/4</span><?= lang(
'Install.form.instance_config',
) ?></h1>
<?= form_label(lang('Install.form.hostname'), 'hostname') ?>
<?= form_input([
'id' => 'hostname',
'name' => 'hostname',
'class' => 'form-input mb-4',
'value' => old(
'hostname',
host_url() === null ? config('App')
->baseURL : host_url(),
),
'required' => 'required',
]) ?>
<div class="flex items-center mb-4">
<span class="inline-flex items-center justify-center w-12 h-12 mr-2 text-sm font-semibold tracking-wider border-4 rounded-full text-pine-700 border-pine-700">1/4</span>
<Heading tagName="h1"><?= lang('Install.form.instance_config') ?></Heading>
</div>
<Forms.Field
name="hostname"
label="<?= lang('Install.form.hostname') ?>"
value="<?= host_url() === null ? config('App')
->baseURL : host_url() ?>"
required="true" />
<?= form_label(
lang('Install.form.media_base_url'),
'media_base_url',
[],
lang('Install.form.media_base_url_hint'),
true,
) ?>
<?= form_input([
'id' => 'media_base_url',
'name' => 'media_base_url',
'class' => 'form-input mb-4',
'value' => old('media_base_url', ''),
]) ?>
<Forms.Field
name="media_base_url"
label="<?= lang('Install.form.media_base_url') ?>"
hint="<?= lang('Install.form.media_base_url_hint') ?>" />
<?= form_label(
lang('Install.form.admin_gateway'),
'admin_gateway',
[],
lang('Install.form.admin_gateway_hint'),
) ?>
<?= form_input([
'id' => 'admin_gateway',
'name' => 'admin_gateway',
'class' => 'form-input mb-4',
'value' => old('admin_gateway', config('Admin')->gateway),
'required' => 'required',
]) ?>
<Forms.Field
name="admin_gateway"
label="<?= lang('Install.form.admin_gateway') ?>"
hint="<?= lang('Install.form.admin_gateway_hint') ?>"
value="<?= config('Admin')
->gateway ?>"
required="true" />
<?= form_label(
lang('Install.form.auth_gateway'),
'auth_gateway',
[],
lang('Install.form.auth_gateway_hint'),
) ?>
<?= form_input([
'id' => 'auth_gateway',
'name' => 'auth_gateway',
'class' => 'form-input mb-6',
'value' => old('auth_gateway', config('Auth')->gateway),
'required' => 'required',
]) ?>
<Forms.Field
name="auth_gateway"
label="<?= lang('Install.form.auth_gateway') ?>"
hint="<?= lang('Install.form.auth_gateway_hint') ?>"
value="<?= config('Auth')
->gateway ?>"
required="true" />
<?= button(
lang('Install.form.next') . icon('arrow-right', 'ml-2'),
'',
[
'variant' => 'primary',
],
[
'type' => 'submit',
'class' => 'self-end',
],
) ?>
<?= form_close() ?>
<Button class="self-end" variant="primary" type="submit" iconRight="arrow-right"><?= lang('Install.form.next') ?></Button>
</form>
<?= $this->endSection() ?>