Loading app/Helpers/breadcrumb_helper.php +1 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,6 @@ if (! function_exists('replace_breadcrumb_params')) { function replace_breadcrumb_params(array $newParams): void { $breadcrumb = Services::breadcrumb(); $breadcrumb->replaceParams(esc($newParams)); $breadcrumb->replaceParams($newParams); } } app/Helpers/components_helper.php +12 −41 Original line number Diff line number Diff line Loading @@ -16,31 +16,6 @@ use CodeIgniter\View\Table; // ------------------------------------------------------------------------ if (! function_exists('hint_tooltip')) { /** * Hint component * * Used to produce tooltip with a question mark icon for hint texts * * @param string $hintText The hint text */ function hint_tooltip(string $hintText = '', string $class = ''): string { $tooltip = '<span data-tooltip="bottom" tabindex="0" title="' . esc($hintText) . '" class="inline-block align-middle opacity-75 focus:ring-accent'; if ($class !== '') { $tooltip .= ' ' . $class; } return $tooltip . '">' . icon('question-fill') . '</span>'; } } // ------------------------------------------------------------------------ if (! function_exists('data_table')) { /** * Data table component Loading Loading @@ -113,12 +88,12 @@ if (! function_exists('publication_pill')) { */ function publication_pill(?Time $publicationDate, string $publicationStatus, string $customClass = ''): string { $class = match ($publicationStatus) { 'published' => 'text-pine-500 border-pine-500 bg-pine-50', 'scheduled' => 'text-red-600 border-red-600 bg-red-50', 'with_podcast' => 'text-blue-600 border-blue-600 bg-blue-50', 'not_published' => 'text-gray-600 border-gray-600 bg-gray-50', default => 'text-gray-600 border-gray-600 bg-gray-50', $variant = match ($publicationStatus) { 'published' => 'success', 'scheduled' => 'warning', 'with_podcast' => 'info', 'not_published' => 'default', default => 'default', }; $title = match ($publicationStatus) { Loading @@ -130,16 +105,12 @@ if (! function_exists('publication_pill')) { $label = lang('Episode.publication_status.' . $publicationStatus); return '<span ' . ($title === '' ? '' : 'title="' . $title . '"') . ' class="flex items-center px-1 font-semibold border rounded w-max ' . $class . ' ' . $customClass . '">' . $label . ($publicationStatus === 'with_podcast' ? icon('error-warning-fill', [ // @icon('error-warning-fill') return '<x-Pill ' . ($title === '' ? '' : 'title="' . $title . '"') . ' variant="' . $variant . '" class="' . $customClass . '">' . $label . ($publicationStatus === 'with_podcast' ? icon('error-warning-fill', [ 'class' => 'flex-shrink-0 ml-1 text-lg', ]) : '') . '</span>'; '</x-Pill>'; } } Loading Loading @@ -182,7 +153,7 @@ if (! function_exists('publication_button')) { } return <<<HTML <Button variant="{$variant}" uri="{$route}" iconLeft="{$iconLeft}" >{$label}</Button> <x-Button variant="{$variant}" uri="{$route}" iconLeft="{$iconLeft}" >{$label}</x-Button> HTML; } } Loading Loading @@ -356,7 +327,7 @@ if (! function_exists('location_link')) { 'class' => 'mr-2 flex-shrink-0', ]) . '<span class="truncate">' . esc($location->name) . '</span>', [ 'class' => 'w-full overflow-hidden inline-flex items-baseline hover:underline focus:ring-accent' . 'class' => 'w-full overflow-hidden inline-flex items-baseline hover:underline' . ($class === '' ? '' : " {$class}"), 'target' => '_blank', 'rel' => 'noreferrer noopener', Loading app/Helpers/page_helper.php +6 −6 Original line number Diff line number Diff line Loading @@ -20,30 +20,30 @@ if (! function_exists('render_page_links')) { { $pages = (new PageModel())->findAll(); $links = anchor(route_to('home'), lang('Common.home'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); if ($podcastHandle !== null) { $links .= anchor(route_to('podcast-links', $podcastHandle), lang('Podcast.links'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); } $links .= anchor(route_to('credits'), lang('Person.credits'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); $links .= anchor(route_to('map'), lang('Page.map.title'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); foreach ($pages as $page) { $links .= anchor($page->link, esc($page->title), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); } // if set in .env, add legal notice link at the end of page links if (config('App')->legalNoticeURL !== null) { $links .= anchor(config('App')->legalNoticeURL, lang('Common.legal_notice'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', 'target' => '_blank', 'rel' => 'noopener noreferrer', ]); Loading app/Libraries/Breadcrumb.php +13 −8 Original line number Diff line number Diff line Loading @@ -32,12 +32,18 @@ class Breadcrumb $uri = ''; foreach (current_url(true)->getSegments() as $segment) { $uri .= '/' . $segment; $this->links[] = [ $link = [ 'text' => is_numeric($segment) ? $segment : lang('Breadcrumb.' . $segment), 'href' => base_url($uri), ]; if (is_numeric($segment)) { $this->links[] = $link; } else { $this->links[$segment] = $link; } } } Loading @@ -46,20 +52,19 @@ class Breadcrumb * * Given a breadcrumb with numeric params, this function replaces them with the values provided in $newParams * * Example with `Home / podcasts / 1 / episodes / 1` * Example with `Home / podcasts / 1 / episodes / 1 / foo` * * $newParams = [ 0 => 'foo', 1 => 'bar' ] replaceParams($newParams); * $newParams = [ 0 => 'bar', 1 => 'baz', 'foo' => 'I Pity The Foo' ] replaceParams($newParams); * * The breadcrumb is now `Home / podcasts / foo / episodes / bar` * The breadcrumb is now `Home / podcasts / foo / episodes / bar / I Pity The Foo` * * @param string[] $newParams */ public function replaceParams(array $newParams): void { foreach ($this->links as $key => $link) { if (is_numeric($link['text'])) { $this->links[$key]['text'] = $newParams[0]; array_shift($newParams); foreach ($newParams as $key => $newValue) { if (array_key_exists($key, $this->links)) { $this->links[$key]['text'] = $newValue; } } } Loading app/Libraries/ViewComponents/Component.php +42 −8 Original line number Diff line number Diff line Loading @@ -4,26 +4,30 @@ declare(strict_types=1); namespace ViewComponents; class Component implements ComponentInterface abstract class Component implements ComponentInterface { protected string $slot = ''; /** * @var list<string> */ protected array $props = []; /** * @var array<string, string|'boolean'|'array'|'number'> */ protected array $casts = []; protected string $class = ''; protected ?string $slot = null; /** * @var array<string, string> */ protected array $attributes = [ 'class' => '', ]; protected array $attributes = []; /** * @param array<string, string> $attributes */ public function __construct(array $attributes) { helper('viewcomponents'); // overwrite default attributes if set $this->attributes = [...$this->attributes, ...$attributes]; Loading @@ -42,9 +46,39 @@ class Component implements ComponentInterface if (is_callable([$this, $method])) { $this->{$method}($value); } else { if (array_key_exists($name, $this->casts)) { $value = match ($this->casts[$name]) { 'boolean' => $value === 'true', 'number' => (int) $value, 'array' => json_decode(htmlspecialchars_decode($value), true), default => $value }; } $this->{$name} = $value; } // remove from attributes if (in_array($name, $this->props, true)) { unset($this->attributes[$name]); } } unset($this->attributes['slot']); } public function mergeClass(string $class): void { if (! array_key_exists('class', $this->attributes)) { $this->attributes['class'] = $class; } else { $this->attributes['class'] .= ' ' . $class; } } public function getStringifiedAttributes(): string { return stringify_attributes($this->attributes); } public function render(): string Loading Loading
app/Helpers/breadcrumb_helper.php +1 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,6 @@ if (! function_exists('replace_breadcrumb_params')) { function replace_breadcrumb_params(array $newParams): void { $breadcrumb = Services::breadcrumb(); $breadcrumb->replaceParams(esc($newParams)); $breadcrumb->replaceParams($newParams); } }
app/Helpers/components_helper.php +12 −41 Original line number Diff line number Diff line Loading @@ -16,31 +16,6 @@ use CodeIgniter\View\Table; // ------------------------------------------------------------------------ if (! function_exists('hint_tooltip')) { /** * Hint component * * Used to produce tooltip with a question mark icon for hint texts * * @param string $hintText The hint text */ function hint_tooltip(string $hintText = '', string $class = ''): string { $tooltip = '<span data-tooltip="bottom" tabindex="0" title="' . esc($hintText) . '" class="inline-block align-middle opacity-75 focus:ring-accent'; if ($class !== '') { $tooltip .= ' ' . $class; } return $tooltip . '">' . icon('question-fill') . '</span>'; } } // ------------------------------------------------------------------------ if (! function_exists('data_table')) { /** * Data table component Loading Loading @@ -113,12 +88,12 @@ if (! function_exists('publication_pill')) { */ function publication_pill(?Time $publicationDate, string $publicationStatus, string $customClass = ''): string { $class = match ($publicationStatus) { 'published' => 'text-pine-500 border-pine-500 bg-pine-50', 'scheduled' => 'text-red-600 border-red-600 bg-red-50', 'with_podcast' => 'text-blue-600 border-blue-600 bg-blue-50', 'not_published' => 'text-gray-600 border-gray-600 bg-gray-50', default => 'text-gray-600 border-gray-600 bg-gray-50', $variant = match ($publicationStatus) { 'published' => 'success', 'scheduled' => 'warning', 'with_podcast' => 'info', 'not_published' => 'default', default => 'default', }; $title = match ($publicationStatus) { Loading @@ -130,16 +105,12 @@ if (! function_exists('publication_pill')) { $label = lang('Episode.publication_status.' . $publicationStatus); return '<span ' . ($title === '' ? '' : 'title="' . $title . '"') . ' class="flex items-center px-1 font-semibold border rounded w-max ' . $class . ' ' . $customClass . '">' . $label . ($publicationStatus === 'with_podcast' ? icon('error-warning-fill', [ // @icon('error-warning-fill') return '<x-Pill ' . ($title === '' ? '' : 'title="' . $title . '"') . ' variant="' . $variant . '" class="' . $customClass . '">' . $label . ($publicationStatus === 'with_podcast' ? icon('error-warning-fill', [ 'class' => 'flex-shrink-0 ml-1 text-lg', ]) : '') . '</span>'; '</x-Pill>'; } } Loading Loading @@ -182,7 +153,7 @@ if (! function_exists('publication_button')) { } return <<<HTML <Button variant="{$variant}" uri="{$route}" iconLeft="{$iconLeft}" >{$label}</Button> <x-Button variant="{$variant}" uri="{$route}" iconLeft="{$iconLeft}" >{$label}</x-Button> HTML; } } Loading Loading @@ -356,7 +327,7 @@ if (! function_exists('location_link')) { 'class' => 'mr-2 flex-shrink-0', ]) . '<span class="truncate">' . esc($location->name) . '</span>', [ 'class' => 'w-full overflow-hidden inline-flex items-baseline hover:underline focus:ring-accent' . 'class' => 'w-full overflow-hidden inline-flex items-baseline hover:underline' . ($class === '' ? '' : " {$class}"), 'target' => '_blank', 'rel' => 'noreferrer noopener', Loading
app/Helpers/page_helper.php +6 −6 Original line number Diff line number Diff line Loading @@ -20,30 +20,30 @@ if (! function_exists('render_page_links')) { { $pages = (new PageModel())->findAll(); $links = anchor(route_to('home'), lang('Common.home'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); if ($podcastHandle !== null) { $links .= anchor(route_to('podcast-links', $podcastHandle), lang('Podcast.links'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); } $links .= anchor(route_to('credits'), lang('Person.credits'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); $links .= anchor(route_to('map'), lang('Page.map.title'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); foreach ($pages as $page) { $links .= anchor($page->link, esc($page->title), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', ]); } // if set in .env, add legal notice link at the end of page links if (config('App')->legalNoticeURL !== null) { $links .= anchor(config('App')->legalNoticeURL, lang('Common.legal_notice'), [ 'class' => 'px-2 py-1 underline hover:no-underline focus:ring-accent', 'class' => 'px-2 py-1 underline hover:no-underline', 'target' => '_blank', 'rel' => 'noopener noreferrer', ]); Loading
app/Libraries/Breadcrumb.php +13 −8 Original line number Diff line number Diff line Loading @@ -32,12 +32,18 @@ class Breadcrumb $uri = ''; foreach (current_url(true)->getSegments() as $segment) { $uri .= '/' . $segment; $this->links[] = [ $link = [ 'text' => is_numeric($segment) ? $segment : lang('Breadcrumb.' . $segment), 'href' => base_url($uri), ]; if (is_numeric($segment)) { $this->links[] = $link; } else { $this->links[$segment] = $link; } } } Loading @@ -46,20 +52,19 @@ class Breadcrumb * * Given a breadcrumb with numeric params, this function replaces them with the values provided in $newParams * * Example with `Home / podcasts / 1 / episodes / 1` * Example with `Home / podcasts / 1 / episodes / 1 / foo` * * $newParams = [ 0 => 'foo', 1 => 'bar' ] replaceParams($newParams); * $newParams = [ 0 => 'bar', 1 => 'baz', 'foo' => 'I Pity The Foo' ] replaceParams($newParams); * * The breadcrumb is now `Home / podcasts / foo / episodes / bar` * The breadcrumb is now `Home / podcasts / foo / episodes / bar / I Pity The Foo` * * @param string[] $newParams */ public function replaceParams(array $newParams): void { foreach ($this->links as $key => $link) { if (is_numeric($link['text'])) { $this->links[$key]['text'] = $newParams[0]; array_shift($newParams); foreach ($newParams as $key => $newValue) { if (array_key_exists($key, $this->links)) { $this->links[$key]['text'] = $newValue; } } } Loading
app/Libraries/ViewComponents/Component.php +42 −8 Original line number Diff line number Diff line Loading @@ -4,26 +4,30 @@ declare(strict_types=1); namespace ViewComponents; class Component implements ComponentInterface abstract class Component implements ComponentInterface { protected string $slot = ''; /** * @var list<string> */ protected array $props = []; /** * @var array<string, string|'boolean'|'array'|'number'> */ protected array $casts = []; protected string $class = ''; protected ?string $slot = null; /** * @var array<string, string> */ protected array $attributes = [ 'class' => '', ]; protected array $attributes = []; /** * @param array<string, string> $attributes */ public function __construct(array $attributes) { helper('viewcomponents'); // overwrite default attributes if set $this->attributes = [...$this->attributes, ...$attributes]; Loading @@ -42,9 +46,39 @@ class Component implements ComponentInterface if (is_callable([$this, $method])) { $this->{$method}($value); } else { if (array_key_exists($name, $this->casts)) { $value = match ($this->casts[$name]) { 'boolean' => $value === 'true', 'number' => (int) $value, 'array' => json_decode(htmlspecialchars_decode($value), true), default => $value }; } $this->{$name} = $value; } // remove from attributes if (in_array($name, $this->props, true)) { unset($this->attributes[$name]); } } unset($this->attributes['slot']); } public function mergeClass(string $class): void { if (! array_key_exists('class', $this->attributes)) { $this->attributes['class'] = $class; } else { $this->attributes['class'] .= ' ' . $class; } } public function getStringifiedAttributes(): string { return stringify_attributes($this->attributes); } public function render(): string Loading