feat(settings): add theme settings to set an accent color for all public pages

set 6 base accent colors: pine, lake, jacaranda, crimson, amber and onyx
This commit is contained in:
Yassine Doghri 2021-11-08 16:52:20 +00:00
parent a746a781b4
commit 5c529a83aa
33 changed files with 389 additions and 199 deletions

View File

@ -447,4 +447,6 @@ class App extends BaseConfig
'192' => '/icon-192.png',
'512' => '/icon-512.png',
];
public string $theme = 'crimson';
}

View File

@ -0,0 +1,26 @@
@layer components {
.color-radio-btn {
@apply absolute opacity-0;
&:focus + label {
@apply ring-accent;
}
&:checked {
@apply ring-2 ring-contrast;
& + label {
@apply flex items-center justify-center text-2xl text-accent-contrast bg-accent-base;
&::before {
content: "✓";
}
}
}
& + label {
@apply inline-block w-16 h-16 text-sm font-semibold rounded-full cursor-pointer border-contrast bg-accent-base text-accent-contrast border-3;
color: hsl(var(--color-text-muted));
}
}
}

View File

@ -1,54 +1,3 @@
/*
--color-brand-lighter: hsl(173 44% 96%);
--color-brand-light: hsl(111 64% 94%);
--color-brand-base: hsl(174 100% 29%);
--color-brand-dark: hsl(172 100% 17%);
--color-brand-darker: hsl(131 100% 12%);
--color-background-elevated: hsl(0 0% 100%);
--color-background-base: hsl(173 44% 96%);
--color-text-base: hsl(240 17% 2%);
--color-text-muted: hsl(240 8% 63%);
--color-text-inverted: hsl(0 0% 100%);
--color-brand-lighter: 173 44% 96%;
--color-brand-light: 111 64% 94%;
--color-brand-base: 174 100% 29%;
--color-brand-dark: 172 100% 17%;
--color-brand-darker: 131 100% 12%;
--color-background-elevated: 0 0% 100%;
--color-background-base: 173 44% 96%;
--color-text-base: 240 17% 2%;
--color-text-muted: 240 8% 63%;
--color-text-inverted: 0 0% 100%;
*/
/*
--color-accent-base: 0 100% 38%;
--color-accent-hover: 0 100% 48%;
--color-accent-muted: 0 8% 63%;
--color-heading-foreground: 0 64% 94%;
--color-heading-background: 0 100% 17%;
--color-background-elevated: 209 35% 15%;
--color-background-base: 210 34% 13%;
--color-background-navigation: 210 34% 11%;
--color-background-header: 200 38% 15%;
--color-background-highlight: 200 38% 25%;
--color-background-backdrop: 0 0% 50%;
--color-border-subtle: 240 8% 27%;
--color-border-contrast: 240 8% 78%;
--color-border-navigation: 210 34% 4%;
--color-text-base: 240 17% 100%;
--color-text-muted: 240 8% 63%;
*/
@layer base {
:root {
--color-accent-base: 174 100% 29%;

View File

@ -2,10 +2,12 @@
@import "./custom.css";
@import "./fonts.css";
@import "./colors.css";
@import "./themes.css";
@import "./breadcrumb.css";
@import "./dropdown.css";
@import "./choices.css";
@import "./radioBtn.css";
@import "./colorRadioBtn.css";
@import "./switch.css";
@import "./radioToggler.css";
@import "./formInputTabs.css";

View File

@ -1,22 +1,22 @@
@layer components {
.form-radio-btn {
@apply absolute mt-3 ml-3 border-contrast border-3 text-accent-base;
}
.form-radio-btn:focus + label {
@apply ring-accent;
}
&:focus {
@apply ring-accent;
}
.form-radio-btn + label {
@apply inline-block py-2 pl-8 pr-2 text-sm font-semibold rounded-lg cursor-pointer border-contrast bg-elevated border-3;
color: hsl(var(--color-text-muted));
}
&:checked {
@apply ring-2 ring-contrast;
.form-radio-btn:checked + label {
@apply text-accent-contrast bg-accent-base;
}
& + label {
@apply text-accent-contrast bg-accent-base;
}
}
.form-radio-btn:checked {
@apply ring-2 ring-contrast;
& + label {
@apply inline-block py-2 pl-8 pr-2 text-sm font-semibold rounded-lg cursor-pointer border-contrast bg-elevated border-3;
color: hsl(var(--color-text-muted));
}
}
}

View File

@ -0,0 +1,139 @@
/* Castopod's brand color */
.theme-pine {
--color-accent-base: 174 100% 29%;
--color-accent-hover: 172 100% 17%;
--color-accent-muted: 131 100% 12%;
--color-accent-contrast: 0 0% 100%;
--color-heading-foreground: 172 100% 17%;
--color-heading-background: 111 64% 94%;
--color-background-elevated: 0 0% 100%;
--color-background-base: 173 44% 96%;
--color-background-navigation: 172 100% 17%;
--color-background-header: 172 100% 17%;
--color-background-highlight: 111 64% 94%;
--color-background-backdrop: 0 0% 50%;
--color-border-subtle: 111 42% 86%;
--color-border-contrast: 0 0% 0%;
--color-border-navigation: 131 100% 12%;
--color-text-base: 158 8% 3%;
--color-text-muted: 172 8% 38%;
}
/* Red / Rose color */
.theme-crimson {
--color-accent-base: 350 87% 61%;
--color-accent-hover: 348 75% 40%;
--color-accent-muted: 348 73% 32%;
--color-accent-contrast: 0 0% 100%;
--color-heading-foreground: 348 73% 32%;
--color-heading-background: 344 79% 96%;
--color-background-elevated: 0 0% 100%;
--color-background-base: 350 44% 96%;
--color-background-header: 348 75% 40%;
--color-background-highlight: 344 79% 96%;
--color-background-backdrop: 0 0% 50%;
--color-border-subtle: 348 42% 86%;
--color-border-contrast: 0 0% 0%;
--color-text-base: 340 8% 3%;
--color-text-muted: 345 8% 38%;
}
/* Blue color */
.theme-lake {
--color-accent-base: 194 100% 44%;
--color-accent-hover: 194 100% 22%;
--color-accent-muted: 195 100% 11%;
--color-accent-contrast: 0 0% 100%;
--color-heading-foreground: 194 100% 22%;
--color-heading-background: 195 100% 92%;
--color-background-elevated: 0 0% 100%;
--color-background-base: 196 44% 96%;
--color-background-header: 194 100% 22%;
--color-background-highlight: 195 100% 92%;
--color-background-backdrop: 0 0% 50%;
--color-border-subtle: 195 42% 86%;
--color-border-contrast: 0 0% 0%;
--color-text-base: 194 8% 3%;
--color-text-muted: 195 8% 38%;
}
/* Orange color */
.theme-amber {
--color-accent-base: 17 100% 57%;
--color-accent-hover: 17 100% 35%;
--color-accent-muted: 17 100% 24%;
--color-accent-contrast: 0 0% 100%;
--color-heading-foreground: 17 100% 35%;
--color-heading-background: 17 100% 89%;
--color-background-elevated: 0 0% 100%;
--color-background-base: 15 44% 96%;
--color-background-header: 17 100% 35%;
--color-background-highlight: 17 100% 89%;
--color-background-backdrop: 0 0% 50%;
--color-border-subtle: 17 42% 86%;
--color-border-contrast: 0 0% 0%;
--color-text-base: 15 8% 3%;
--color-text-muted: 17 8% 38%;
}
/* Violet color */
.theme-jacaranda {
--color-accent-base: 254 72% 52%;
--color-accent-hover: 254 73% 30%;
--color-accent-muted: 254 71% 19%;
--color-accent-contrast: 0 0% 100%;
--color-heading-foreground: 254 73% 30%;
--color-heading-background: 254 73% 84%;
--color-background-elevated: 0 0% 100%;
--color-background-base: 253 44% 96%;
--color-background-header: 254 73% 30%;
--color-background-highlight: 254 88% 91%;
--color-background-backdrop: 0 0% 50%;
--color-border-subtle: 254 42% 86%;
--color-border-contrast: 0 0% 0%;
--color-text-base: 253 8% 3%;
--color-text-muted: 254 8% 38%;
}
/* Black color */
.theme-onyx {
--color-accent-base: 240 17% 2%;
--color-accent-hover: 240 17% 17%;
--color-accent-muted: 240 17% 17%;
--color-accent-contrast: 0 0% 100%;
--color-heading-foreground: 240 17% 17%;
--color-heading-background: 240 17% 94%;
--color-background-elevated: 0 0% 100%;
--color-background-base: 240 17% 96%;
--color-background-header: 240 12% 17%;
--color-background-highlight: 240 17% 94%;
--color-background-backdrop: 0 0% 50%;
--color-border-subtle: 240 17% 86%;
--color-border-contrast: 0 0% 0%;
--color-text-base: 240 8% 3%;
--color-text-muted: 240 8% 38%;
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Views\Components\Forms;
class ColorRadioButton extends FormComponent
{
protected bool $isChecked = false;
public function setIsChecked(string $value): void
{
$this->isChecked = $value === 'true';
}
public function render(): string
{
$radioInput = form_radio(
[
'id' => $this->value,
'name' => $this->name,
'class' => 'color-radio-btn',
],
$this->value,
old($this->name) ? old($this->name) === $this->value : $this->isChecked,
);
return <<<HTML
<div class="{$this->class}">
{$radioInput}
<label for="{$this->value}" title="{$this->slot}" data-tooltip="bottom"></label>
</div>
HTML;
}
}

View File

@ -31,6 +31,14 @@ $routes->group(
'as' => 'settings-instance-delete-icon',
'filter' => 'permission:settings-manage',
]);
$routes->get('theme', 'SettingsController::theme', [
'as' => 'settings-theme',
'filter' => 'permission:settings-manage',
]);
$routes->post('theme', 'SettingsController::attemptSetInstanceTheme', [
'as' => 'settings-theme',
'filter' => 'permission:settings-manage',
]);
});
$routes->group('persons', function ($routes): void {

View File

@ -88,7 +88,7 @@ class SettingsController extends BaseController
]);
}
return redirect()->back();
return redirect('settings-general')->with('message', lang('Settings.general.instanceEditSuccess'));
}
public function deleteIcon(): RedirectResponse
@ -100,6 +100,25 @@ class SettingsController extends BaseController
service('settings')
->forget('App.siteIcon');
return redirect()->back();
return redirect('settings-general')->with('message', lang('Settings.general.deleteIconSuccess'));
}
public function theme(): string
{
helper('form');
return view('settings/theme');
}
public function attemptSetInstanceTheme(): RedirectResponse
{
$theme = $this->request->getPost('theme');
service('settings')
->set('App.theme', $theme);
// delete all pages cache
cache()
->deleteMatching('page*');
return redirect('settings-theme')->with('message', lang('Settings.theme.setInstanceThemeSuccess'));
}
}

View File

@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
return [
'go_to_website' => 'View site',
'go_to_admin' => 'Go to admin',
'dashboard' => 'Dashboard',
'admin' => 'Home',
'podcasts' => 'Podcasts',
'podcast-list' => 'All podcasts',
'podcast-create' => 'New podcast',
'podcast-import' => 'Import a podcast',
'persons' => 'Persons',
'person-list' => 'All persons',
'person-create' => 'New person',
'fediverse' => 'Fediverse',
'fediverse-blocked-actors' => 'Blocked accounts',
'fediverse-blocked-domains' => 'Blocked domains',
'users' => 'Users',
'user-list' => 'All users',
'user-create' => 'New user',
'pages' => 'Pages',
'page-list' => 'All pages',
'page-create' => 'New Page',
'settings' => 'Settings',
'settings-general' => 'General',
'account' => [
'my-account' => 'My account',
'change-password' => 'Change password',
'logout' => 'Logout',
],
];

View File

@ -17,6 +17,7 @@ return [
'contributors' => 'contributors',
'pages' => 'pages',
'settings' => 'settings',
'theme' => 'theme',
'add' => 'add',
'new' => 'new',
'edit' => 'edit',

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
return [
'go_to_website' => 'View site',
'go_to_admin' => 'Go to admin',
'dashboard' => 'Dashboard',
'admin' => 'Home',
'podcasts' => 'Podcasts',
@ -28,6 +29,9 @@ return [
'pages' => 'Pages',
'page-list' => 'All pages',
'page-create' => 'New Page',
'settings' => 'Settings',
'settings-general' => 'General',
'settings-theme' => 'Theme',
'account' => [
'my-account' => 'My account',
'change-password' => 'Change password',

View File

@ -10,7 +10,7 @@ declare(strict_types=1);
return [
'title' => 'General settings',
'form' => [
'general' => [
'site_section_title' => 'Instance',
'site_icon' => 'Site icon',
'site_icon_delete' => 'Delete site icon',
@ -19,5 +19,20 @@ return [
'site_name' => 'Site name',
'site_description' => 'Site description',
'submit' => 'Save',
'instanceEditSuccess' => 'Instance has been updated successfully!',
'deleteIconSuccess' => 'Site icon has been remove successfully!',
],
'theme' => [
'title' => 'Theme',
'accent_section_title' => 'Accent color',
'accent_section_subtitle' => 'Choose the color to determine the look and feel of all public pages.',
'pine' => 'Pine',
'crimson' => 'Crimson',
'amber' => 'Amber',
'lake' => 'Lake',
'jacaranda' => 'Jacaranda',
'onyx' => 'Onyx',
'submit' => 'Save',
'setInstanceThemeSuccess' => 'Theme has been updated successfully!',
],
];

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
return [
'go_to_website' => 'Visiter le site',
'dashboard' => 'Tableau de bord',
'admin' => 'Accueil',
'podcasts' => 'Podcasts',
'podcast-list' => 'Tous les podcasts',
'podcast-create' => 'Créer un podcast',
'podcast-import' => 'Importer un podcast',
'persons' => 'Intervenants',
'person-list' => 'Tous les intervenants',
'person-create' => 'Nouvel intervenant',
'fediverse' => 'Fédiverse',
'fediverse-blocked_actors' => 'Utilisateurs blockés',
'fediverse-blocked_domains' => 'Domaines blockés',
'users' => 'Utilisateurs',
'user-list' => 'Tous les utilisateurs',
'user-create' => 'Créer un utilisateur',
'pages' => 'Pages',
'page-list' => 'Toutes les pages',
'page-create' => 'Créer une page',
'settings' => 'Paramètres',
'settings-general' => 'Général',
'account' => [
'my-account' => 'Mon compte',
'change-password' => 'Modifier le mot de passe',
'logout' => 'Déconnexion',
],
];

View File

@ -16,6 +16,8 @@ return [
'episodes' => 'épisodes',
'contributors' => 'contributeurs',
'pages' => 'pages',
'settings' => 'paramètres',
'theme' => 'thème',
'add' => 'ajouter',
'new' => 'créer',
'edit' => 'modifier',

View File

@ -28,6 +28,9 @@ return [
'pages' => 'Pages',
'page-list' => 'Toutes les pages',
'page-create' => 'Créer une page',
'settings' => 'Paramètres',
'settings-general' => 'Général',
'settings-themes' => 'Thèmes',
'account' => [
'my-account' => 'Mon compte',
'change-password' => 'Modifier le mot de passe',

View File

@ -10,15 +10,28 @@ declare(strict_types=1);
return [
'title' => 'Paramètres généraux',
'form' => [
'general' => [
'site_section_title' => 'Instance',
'site_section_subtitle' => 'configuration de linstance',
'site_icon' => 'Favicon du site',
'site_icon_delete' => 'Supprimer la favicon du site',
'site_icon_hint' => 'Les favicons sont ce que vous voyez sur les onglets de votre navigateur, dans votre barre de favoris, et lorsque vous ajoutez un site web en raccourci sur des appareils mobiles.',
'site_icon_helper' => 'La favicon doit être carrée, avec au minimum 512px de largeur et de hauteur.',
'site_name' => 'Titre du site',
'site_description' => 'Description du site',
'submit' => 'Save',
'submit' => 'Sauvegarder',
'instanceEditSuccess' => 'Linstance a bien été mise à jour!',
'deleteIconSuccess' => 'La favicon du site a bien été retirée!',
],
'theme' => [
'title' => 'Thème',
'accent_section_title' => 'Couleur daccentuation',
'accent_section_subtitle' => 'Sélectionnez une couleur qui déterminera lapparence de toutes les pages publiques.',
'pine' => 'Pin',
'crimson' => 'Cramoisi',
'amber' => 'Ambre',
'lake' => 'Lac',
'jacaranda' => 'Jacaranda',
'onyx' => 'Onyx',
'setInstanceThemeSuccess' => 'Le thème a bien été mis à jour!',
],
];

View File

@ -107,6 +107,7 @@ module.exports = {
podcastMain: "1fr minmax(200px, 300px)",
cards: "repeat(auto-fill, minmax(14rem, 1fr))",
latestEpisodes: "repeat(5, 1fr)",
colorButtons: "repeat(auto-fill, minmax(4rem, 1fr))",
},
gridTemplateRows: {
admin: "40px 1fr",

View File

@ -11,7 +11,7 @@
<a href="<?= route_to(
'home',
) ?>" class="inline-flex items-center h-full px-6 text-sm font-semibold hover:underline focus:ring-inset focus:ring-accent">
<?= lang('AdminNavigation.go_to_website') ?>
<?= lang('Navigation.go_to_website') ?>
<?= icon('external-link', 'ml-1 opacity-60') ?>
</a>
</div>
@ -48,12 +48,12 @@
$menuItems = [
[
'type' => 'link',
'title' => lang('AdminNavigation.account.my-account'),
'title' => lang('Navigation.account.my-account'),
'uri' => route_to('my-account'),
],
[
'type' => 'link',
'title' => lang('AdminNavigation.account.change-password'),
'title' => lang('Navigation.account.change-password'),
'uri' => route_to('change-password'),
],
[
@ -61,7 +61,7 @@
],
[
'type' => 'link',
'title' => lang('AdminNavigation.account.logout'),
'title' => lang('Navigation.account.logout'),
'uri' => route_to('logout'),
],
];

View File

@ -24,7 +24,7 @@ $navigation = [
],
'settings' => [
'icon' => 'settings',
'items' => ['settings-general'],
'items' => ['settings-general', 'settings-theme'],
],
]; ?>
@ -33,7 +33,7 @@ $navigation = [
<div>
<button class="inline-flex items-center w-full px-4 py-1 font-semibold focus:ring-accent" type="button">
<?= icon($data['icon'], 'opacity-60 text-2xl mr-4') ?>
<?= lang('AdminNavigation.' . $section) ?>
<?= lang('Navigation.' . $section) ?>
</button>
<ul class="flex flex-col">
<?php foreach ($data['items'] as $item): ?>
@ -42,7 +42,7 @@ $navigation = [
<a class="w-full py-1 pl-14 pr-2 text-sm hover:opacity-100 focus:ring-inset focus:ring-accent<?= $isActive
? ' font-semibold opacity-100 inline-flex items-center'
: ' opacity-75' ?>" href="<?= route_to($item) ?>"><?= ($isActive ? icon('chevron-right', 'mr-2') : '') . lang(
'AdminNavigation.' . $item,
'Navigation.' . $item,
) ?></a>
</li>
<?php endforeach; ?>

View File

@ -14,11 +14,11 @@
<?= csrf_field() ?>
<Forms.Section
title="<?= lang('Settings.form.site_section_title') ?>">
title="<?= lang('Settings.general.site_section_title') ?>">
<Forms.Field
name="site_name"
label="<?= lang('Settings.form.site_name') ?>"
label="<?= lang('Settings.general.site_name') ?>"
value="<?= service('settings')
->get('App.siteName') ?>"
required="true" />
@ -26,7 +26,7 @@
<Forms.Field
as="Textarea"
name="site_description"
label="<?= lang('Settings.form.site_description') ?>"
label="<?= lang('Settings.general.site_description') ?>"
value="<?= service('settings')
->get('App.siteDescription') ?>"
required="true"
@ -36,21 +36,21 @@
<Forms.Field
name="site_icon"
type="file"
label="<?= lang('Settings.form.site_icon') ?>"
hint="<?= lang('Settings.form.site_icon_hint') ?>"
helper="<?= lang('Settings.form.site_icon_helper') ?>"
label="<?= lang('Settings.general.site_icon') ?>"
hint="<?= lang('Settings.general.site_icon_hint') ?>"
helper="<?= lang('Settings.general.site_icon_helper') ?>"
accept=".png,.jpeg,.jpg"
class="flex-1"
/>
<?php if (config('App')->siteIcon['ico'] !== service('settings')->get('App.siteIcon')['ico']): ?>
<div class="relative ml-2">
<a href="<?= route_to('settings-instance-delete-icon') ?>" class="absolute p-1 text-red-700 bg-red-100 border-2 rounded-full hover:text-red-900 border-contrast -top-3 -right-3 focus:ring-accent" title="<?= lang('Settings.form.site_icon_delete') ?>" data-tooltip="top"><?= icon('delete-bin') ?></a>
<a href="<?= route_to('settings-instance-delete-icon') ?>" class="absolute p-1 text-red-700 bg-red-100 border-2 rounded-full hover:text-red-900 border-contrast -top-3 -right-3 focus:ring-accent" title="<?= lang('Settings.general.site_icon_delete') ?>" data-tooltip="top"><?= icon('delete-bin') ?></a>
<img src="<?= service('settings')->get('App.siteIcon')['64'] ?>" alt="<?= service('settings')->get('App.siteName') ?> Favicon" class="w-10 h-10" />
</div>
<?php endif; ?>
</div>
<Button variant="primary" type="submit" class="self-end"><?= lang('Settings.form.submit') ?></Button>
<Button variant="primary" type="submit" class="self-end"><?= lang('Settings.general.submit') ?></Button>
</Forms.Section>

View File

@ -0,0 +1,34 @@
<?= $this->extend('_layout') ?>
<?= $this->section('title') ?>
<?= lang('Settings.theme.title') ?>
<?= $this->endSection() ?>
<?= $this->section('pageTitle') ?>
<?= lang('Settings.theme.title') ?>
<?= $this->endSection() ?>
<?= $this->section('content') ?>
<form action="<?= route_to('settings-theme') ?>" method="POST" class="flex flex-col gap-y-4" enctype="multipart/form-data">
<?= csrf_field() ?>
<Forms.Section
title="<?= lang('Settings.theme.accent_section_title') ?>"
subtitle="<?= lang('Settings.theme.accent_section_subtitle') ?>">
<div class="grid gap-4 grid-cols-colorButtons">
<?php foreach (['pine', 'lake', 'jacaranda', 'crimson', 'amber', 'onyx'] as $theme): ?>
<Forms.ColorRadioButton
class="theme-<?= $theme ?> mx-auto"
value="<?= $theme ?>"
name="theme"
isChecked="<?= $theme === service('settings')->get('App.theme') ? 'true' : 'false' ?>" ><?= lang('Settings.theme.' . $theme) ?></Forms.ColorRadioButton>
<?php endforeach; ?>
</div>
<Button variant="primary" type="submit" class="self-end"><?= lang('Settings.theme.submit') ?></Button>
</Forms.Section>
</form>
<?= $this->endSection() ?>

View File

@ -4,7 +4,7 @@
<?= svg('castopod-logo-base', 'h-6') ?>
</a>
<a href="<?= route_to('admin', ) ?>" class="inline-flex items-center h-full px-6 text-sm font-semibold hover:underline focus:ring-inset focus:ring-accent">
<?= lang('AdminNavigation.go_to_admin') ?>
<?= lang('Navigation.go_to_admin') ?>
<?= icon('external-link', 'ml-1 opacity-60') ?>
</a>
</div>
@ -43,12 +43,12 @@
$menuItems = [
[
'type' => 'link',
'title' => lang('AdminNavigation.account.my-account'),
'title' => lang('Navigation.account.my-account'),
'uri' => route_to('my-account'),
],
[
'type' => 'link',
'title' => lang('AdminNavigation.account.change-password'),
'title' => lang('Navigation.account.change-password'),
'uri' => route_to('change-password'),
],
[
@ -56,7 +56,7 @@
],
[
'type' => 'link',
'title' => lang('AdminNavigation.account.logout'),
'title' => lang('Navigation.account.logout'),
'uri' => route_to('logout'),
],
];

View File

@ -29,12 +29,13 @@
->asset('js/audio-player.ts', 'js') ?>
</head>
<body class="flex flex-col min-h-screen mx-auto bg-base">
<body class="flex flex-col min-h-screen mx-auto bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<?php if (service('authentication')->check()): ?>
<?= $this->include('_admin_navbar') ?>
<?php endif; ?>
<header class="py-8 text-white border-b bg-elevated border-subtle">
<header class="py-8 border-b bg-elevated border-subtle">
<div class="container flex flex-col items-start px-2 py-4 mx-auto">
<a href="<?= route_to('home') ?>"
class="inline-flex items-center mb-2 text-sm focus:ring-accent"><?= icon(

View File

@ -27,7 +27,8 @@
->asset('js/audio-player.ts', 'js') ?>
</head>
<body class="flex flex-col min-h-screen mx-auto md:min-h-full md:grid md:grid-cols-podcast bg-base">
<body class="flex flex-col min-h-screen mx-auto md:min-h-full md:grid md:grid-cols-podcast bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<?php if (can_user_interact()): ?>
<div class="col-span-full">
<?= $this->include('_admin_navbar') ?>

View File

@ -28,7 +28,8 @@
->asset('js/app.ts', 'js') ?>
</head>
<body class="flex flex-col min-h-screen mx-auto bg-base">
<body class="flex flex-col min-h-screen mx-auto bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<?php if (service('authentication')->check()): ?>
<?= $this->include('_admin_navbar') ?>
<?php endif; ?>
@ -37,14 +38,16 @@
<div class="container flex items-center justify-between px-2 py-4 mx-auto">
<a href="<?= route_to(
'home',
) ?>" class="inline-flex items-baseline text-3xl font-semibold font-display"><?= 'castopod' .
svg('castopod-logo-base', 'h-6 ml-2') ?></a>
) ?>" class="inline-flex items-baseline text-3xl font-semibold font-display"><?= service('settings')
->get('App.siteName') === 'Castopod' ? 'castopod' .
svg('castopod-logo-base', 'h-6 ml-2') : service('settings')
->get('App.siteName') ?></a>
</div>
</header>
<main class="container flex-1 px-4 py-10 mx-auto">
<Heading class="inline-block mb-2"><?= lang('Home.all_podcasts') ?> (<?= count(
$podcasts,
) ?>)</Heading>
$podcasts,
) ?>)</Heading>
<section class="grid gap-4 grid-cols-cards">
<?php if ($podcasts): ?>
<?php foreach ($podcasts as $podcast): ?>

View File

@ -20,12 +20,13 @@
->asset('js/map.ts', 'js') ?>
</head>
<body class="flex flex-col h-full min-h-screen mx-auto bg-base">
<body class="flex flex-col h-full min-h-screen mx-auto bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<?php if (service('authentication')->check()): ?>
<?= $this->include('_admin_navbar') ?>
<?php endif; ?>
<header class="py-8 text-white border-b border-subtle bg-elevated">
<header class="py-8 border-b border-subtle bg-elevated">
<div class="container flex flex-col items-start px-2 py-4 mx-auto">
<a href="<?= route_to('home') ?>"
class="inline-flex items-center mb-2 text-sm focus:ring-accent"><?= icon(

View File

@ -17,7 +17,8 @@
->asset('js/app.ts', 'js') ?>
</head>
<body class="flex flex-col min-h-screen mx-auto bg-base">
<body class="flex flex-col min-h-screen mx-auto bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<?php if (service('authentication')->check()): ?>
<?= $this->include('_admin_navbar') ?>
<?php endif; ?>
@ -29,7 +30,7 @@
'arrow-left',
'mr-2',
) . lang('Page.back_to_home') ?></a>
<h1 class="text-3xl font-semibold"><?= $page->title ?></h1>
<Heading tagName="h1" class="text-3xl font-semibold"><?= $page->title ?></Heading>
</div>
</header>
<main class="container flex-1 px-4 py-10 mx-auto">

View File

@ -27,7 +27,8 @@
->asset('js/audio-player.ts', 'js') ?>
</head>
<body class="flex flex-col min-h-screen mx-auto md:min-h-full md:grid md:grid-cols-podcast bg-base">
<body class="flex flex-col min-h-screen mx-auto md:min-h-full md:grid md:grid-cols-podcast bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<?php if (can_user_interact()): ?>
<div class="col-span-full">
<?= $this->include('_admin_navbar') ?>

View File

@ -14,7 +14,7 @@
data-toggle="funding-links"
data-toggle-class="hidden"
aria-label="<?= lang('Common.close') ?>"
class="self-start p-1 text-2xl"><?= icon('close') ?></button>
class="self-start p-1 text-2xl rounded-full focus:ring-accent"><?= icon('close') ?></button>
</div>
<div class="flex flex-col items-start p-4 space-y-4">
<?php foreach ($podcast->fundingPlatforms as $fundingPlatform): ?>
@ -24,7 +24,7 @@
title="<?= $fundingPlatform->link_content ?>"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center font-semibold text-accent-base">
class="inline-flex items-center font-semibold text-accent-base hover:text-accent-hover focus:ring-accent">
<?= icon(
$fundingPlatform->type .
'/' .

View File

@ -33,13 +33,13 @@
<div class="px-2 sm:px-4">
<div class="mb-2"><?= $podcast->description_html ?></div>
<div class="flex gap-x-4 gap-y-2">
<span class="px-2 py-1 text-sm font-semibold border rounded-sm border-subtle bg-highlight text-skin-muted">
<span class="px-2 py-1 text-sm font-semibold border rounded-sm border-subtle bg-highlight">
<?= lang(
'Podcast.category_options.' . $podcast->category->code,
) ?>
</span>
<?php foreach ($podcast->other_categories as $other_category): ?>
<span class="px-2 py-1 text-sm font-semibold border rounded-sm border-subtle bg-highlight text-skin-muted">
<span class="px-2 py-1 text-sm font-semibold border rounded-sm border-subtle bg-highlight">
<?= lang(
'Podcast.category_options.' . $other_category->code,
) ?>

View File

@ -33,9 +33,10 @@
</head>
<body class="flex flex-col min-h-screen bg-base">
<body class="flex flex-col min-h-screen bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<header class="flex flex-col items-center mb-8">
<h1 class="w-full pt-8 pb-32 text-lg font-semibold text-center text-skin-base bg-elevated"><?= lang(
<h1 class="w-full pt-8 pb-32 text-lg font-semibold text-center text-white bg-header"><?= lang(
'Fediverse.follow.subtitle',
) ?></h1>
<div class="flex flex-col w-full max-w-xs -mt-24 overflow-hidden shadow bg-elevated rounded-xl">
@ -52,7 +53,7 @@
</header>
<main class="w-full max-w-md px-4 mx-auto">
<form action="<?= 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 gap-y-2">
<?= csrf_field() ?>
<?= view('_message_block') ?>
@ -62,18 +63,15 @@
hint="<?= lang('Fediverse.your_handle_hint') ?>"
required="true"
/>
<Button variant="primary" type="submit" class="self-end mt-2" iconRight="send-plane"><?= lang('Fediverse.follow.submit') ?></Button>
<Button variant="primary" type="submit" class="self-end" iconRight="send-plane"><?= lang('Fediverse.follow.submit') ?></Button>
</form>
</main>
<footer
class="container flex flex-col items-center px-2 py-4 mx-auto mt-auto text-xs border-t md:justify-between md:flex-row">
<?= render_page_links('inline-flex mb-4 md:mb-0') ?>
<p>
<?= lang('Common.powered_by', [
'castopod' =>
'<a class="inline-flex font-semibold hover:underline focus:ring-accent" href="https://castopod.org" target="_blank" rel="noreferrer noopener">Castopod' . icon('social/castopod', 'ml-1 text-lg') . '</a>',
]) ?>
</p>
class="flex-col w-full px-2 py-4 mt-auto text-xs text-center border-t text-skin-muted border-subtle">
<?= lang('Common.powered_by', [
'castopod' =>
'<a class="inline-flex font-semibold hover:underline focus:ring-accent" href="https://castopod.org" target="_blank" rel="noreferrer noopener">Castopod' . icon('social/castopod', 'ml-1 text-lg') . '</a>',
]) ?>
</footer>
</body>

View File

@ -34,9 +34,10 @@
->asset('js/podcast.ts', 'js') ?>
</head>
<body class="min-h-screen mx-auto bg-base">
<header class="pt-8 pb-32 bg-elevated">
<h1 class="text-lg font-semibold text-center text-skin-base"><?= lang(
<body class="flex flex-col min-h-screen mx-auto bg-base theme-<?= service('settings')
->get('App.theme') ?>">
<header class="pt-8 pb-32 bg-header">
<h1 class="text-lg font-semibold text-center text-white"><?= lang(
'Fediverse.' . $action . '.subtitle',
) ?></h1>
</header>
@ -47,7 +48,7 @@
'post' => $post,
]) ?>
<form action="<?= route_to('post-attempt-remote-action', $post->id, $action) ?>" method="POST" class="flex flex-col mt-8">
<form action="<?= route_to('post-attempt-remote-action', $post->id, $action) ?>" method="POST" class="flex flex-col mt-8 gap-y-2">
<?= csrf_field() ?>
<?= view('_message_block') ?>
@ -60,4 +61,11 @@
<Button variant="primary" type="submit" class="self-end" iconRight="send-plane"><?= lang('Fediverse.' . $action . '.submit') ?></Button>
</form>
</main>
<footer
class="flex-col w-full px-2 py-4 mt-auto text-xs text-center border-t text-skin-muted border-subtle">
<?= lang('Common.powered_by', [
'castopod' =>
'<a class="inline-flex font-semibold hover:underline focus:ring-accent" href="https://castopod.org" target="_blank" rel="noreferrer noopener">Castopod' . icon('social/castopod', 'ml-1 text-lg') . '</a>',
]) ?>
</footer>
</body>