From 5c56f3e6f00a61af2ccf50811c155c325f2b10fa Mon Sep 17 00:00:00 2001 From: Yassine Doghri <yassine@doghri.fr> Date: Tue, 26 Oct 2021 15:54:56 +0000 Subject: [PATCH] feat(settings): add general config for instance (site name, description and icon) --- .gitignore | 2 + app/Config/App.php | 20 +++ app/Config/Routes.php | 6 +- app/Controllers/WebmanifestController.php | 45 ++++++ app/Database/Seeds/AuthSeeder.php | 12 ++ app/Helpers/media_helper.php | 3 + composer.json | 8 +- composer.lock | 153 ++++++++++++++---- ecs.php | 1 - modules/Admin/Config/Routes.php | 15 ++ .../Admin/Controllers/SettingsController.php | 105 ++++++++++++ modules/Admin/Language/en/AdminNavigation.php | 2 + modules/Admin/Language/en/Breadcrumb.php | 1 + modules/Admin/Language/en/Settings.php | 23 +++ modules/Admin/Language/fr/AdminNavigation.php | 2 + modules/Admin/Language/fr/Settings.php | 24 +++ .../Install/Controllers/InstallController.php | 2 + public/favicon.ico | Bin 16958 -> 21238 bytes public/icon-180.png | Bin 0 -> 17522 bytes public/icon-192.png | Bin 0 -> 5913 bytes public/icon-512.png | Bin 0 -> 7340 bytes public/icon-64.png | Bin 0 -> 738 bytes public/icon.png | Bin 0 -> 7027 bytes themes/cp_admin/_layout.php | 5 +- themes/cp_admin/_sidebar.php | 4 + themes/cp_admin/person/edit.php | 1 + themes/cp_admin/settings/general.php | 59 +++++++ themes/cp_app/_layout.php | 15 +- themes/cp_app/embed.php | 5 +- themes/cp_app/episode/_layout.php | 5 +- themes/cp_app/home.php | 19 ++- themes/cp_app/map.php | 5 +- themes/cp_app/page.php | 5 +- themes/cp_app/podcast/_layout.php | 5 +- themes/cp_app/podcast/about.php | 5 +- themes/cp_app/podcast/activity.php | 5 +- themes/cp_app/podcast/episodes.php | 5 +- themes/cp_app/podcast/follow.php | 6 +- themes/cp_app/post/remote_action.php | 5 +- themes/cp_auth/_layout.php | 2 +- themes/cp_install/_layout.php | 5 +- 41 files changed, 533 insertions(+), 52 deletions(-) create mode 100644 app/Controllers/WebmanifestController.php create mode 100644 modules/Admin/Controllers/SettingsController.php create mode 100644 modules/Admin/Language/en/Settings.php create mode 100644 modules/Admin/Language/fr/Settings.php create mode 100644 public/icon-180.png create mode 100644 public/icon-192.png create mode 100644 public/icon-512.png create mode 100644 public/icon-64.png create mode 100644 public/icon.png create mode 100644 themes/cp_admin/settings/general.php diff --git a/.gitignore b/.gitignore index 47f4c37308..4ed935bc0b 100644 --- a/.gitignore +++ b/.gitignore @@ -137,9 +137,11 @@ node_modules # public folder public/* +public/media/site !public/media !public/.htaccess !public/favicon.ico +!public/icon* !public/index.php !public/robots.txt diff --git a/app/Config/App.php b/app/Config/App.php index df445db0ed..4d2227c087 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -427,4 +427,24 @@ class App extends BaseConfig * Defines the root folder for media files storage */ public string $mediaRoot = 'media'; + + /** + * -------------------------------------------------------------------------- + * Instance / Site Config + * -------------------------------------------------------------------------- + */ + public string $siteName = 'Castopod'; + + public string $siteDescription = 'Castopod Host is an open-source hosting platform made for podcasters who want engage and interact with their audience.'; + + /** + * @var array<int|string, string> + */ + public array $siteIcon = [ + 'ico' => '/favicon.ico', + '64' => '/icon-64.png', + '180' => '/icon-180.png', + '192' => '/icon-192.png', + '512' => '/icon-512.png', + ]; } diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 45eff6b951..7d2ca19f73 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -48,9 +48,13 @@ $routes->addPlaceholder( * -------------------------------------------------------------------- */ +$routes->get('manifest.webmanifest', 'WebmanifestController', [ + 'as' => 'webmanifest', +]); + // We get a performance increase by specifying the default // route since we don't have to scan directories. -$routes->get('/', 'HomeController::index', [ +$routes->get('/', 'HomeController', [ 'as' => 'home', ]); diff --git a/app/Controllers/WebmanifestController.php b/app/Controllers/WebmanifestController.php new file mode 100644 index 0000000000..dd320e440e --- /dev/null +++ b/app/Controllers/WebmanifestController.php @@ -0,0 +1,45 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2020 Podlibre + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +namespace App\Controllers; + +use CodeIgniter\Controller; +use CodeIgniter\HTTP\ResponseInterface; + +class WebmanifestController extends Controller +{ + public function index(): ResponseInterface + { + $webmanifest = [ + 'name' => service('settings') + ->get('App.siteName'), + 'description' => service('settings') + ->get('App.siteDescription'), + 'display' => 'minimal-ui', + 'theme_color' => '#009486', + 'icons' => [ + [ + 'src' => service('settings') + ->get('App.siteIcon')['192'], + 'type' => 'image/png', + 'sizes' => '192x192', + ], + [ + 'src' => service('settings') + ->get('App.siteIcon')['512'], + 'type' => 'image/png', + 'sizes' => '512x512', + ], + ], + ]; + + return $this->response->setJSON($webmanifest); + } +} diff --git a/app/Database/Seeds/AuthSeeder.php b/app/Database/Seeds/AuthSeeder.php index 2fb6fb6a28..eb9af6a760 100644 --- a/app/Database/Seeds/AuthSeeder.php +++ b/app/Database/Seeds/AuthSeeder.php @@ -40,6 +40,18 @@ class AuthSeeder extends Seeder * @var array<string, array<string, string|array>[]> */ protected array $permissions = [ + 'settings' => [ + [ + 'name' => 'view', + 'description' => 'View settings options', + 'has_permission' => ['superadmin'], + ], + [ + 'name' => 'manage', + 'description' => 'Update general settings', + 'has_permission' => ['superadmin'], + ], + ], 'users' => [ [ 'name' => 'create', diff --git a/app/Helpers/media_helper.php b/app/Helpers/media_helper.php index 312af42a3b..b9a1c65bf7 100644 --- a/app/Helpers/media_helper.php +++ b/app/Helpers/media_helper.php @@ -29,6 +29,9 @@ if (! function_exists('save_media')) { if (! file_exists($mediaRoot)) { mkdir($mediaRoot, 0777, true); + } + + if (! file_exists($mediaRoot . '/index.html')) { touch($mediaRoot . '/index.html'); } diff --git a/composer.json b/composer.json index 3ca24a4fc5..b7dffcaf40 100644 --- a/composer.json +++ b/composer.json @@ -12,15 +12,17 @@ "geoip2/geoip2": "^v2.11.0", "myth/auth": "dev-develop", "codeigniter4/codeigniter4": "dev-develop", - "league/commonmark": "^1.6.6", + "league/commonmark": "^v1.6.6", "vlucas/phpdotenv": "^v5.3.0", - "league/html-to-markdown": "^5.0.0", + "league/html-to-markdown": "^v5.0.1", "opawg/user-agents-php": "^v1.0", "podlibre/ipcat": "^v1.0", "podlibre/podcast-namespace": "^v1.0.6", "phpseclib/phpseclib": "~2.0.30", "michalsn/codeigniter4-uuid": "dev-develop", - "essence/essence": "^3.5.4" + "essence/essence": "^3.5.4", + "codeigniter4/settings": "dev-develop", + "chrisjean/php-ico": "^1.0" }, "require-dev": { "mikey179/vfsstream": "^v1.6.8", diff --git a/composer.lock b/composer.lock index 03baaec32b..82b1287a71 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "af4a438816f7adbbd6950d93ed333e9f", + "content-hash": "f35a050323bdc632cd550f9d13f0679c", "packages": [ { "name": "brick/math", @@ -60,6 +60,46 @@ ], "time": "2021-01-20T22:51:39+00:00" }, + { + "name": "chrisjean/php-ico", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/chrisbliss18/php-ico.git", + "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/chrisbliss18/php-ico/zipball/ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6", + "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "php": ">=5.2.4" + }, + "type": "library", + "autoload": { + "classmap": ["class-php-ico.php"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["GPL-2.0+"], + "authors": [ + { + "name": "Chris Jean", + "homepage": "https://chrisjean.com", + "role": "Developer" + } + ], + "description": "An easy-to-use library to generate valid ICO files.", + "homepage": "https://github.com/chrisbliss18/php-ico", + "keywords": ["favicon", "ico"], + "support": { + "issues": "https://github.com/chrisbliss18/php-ico/issues", + "source": "https://github.com/chrisbliss18/php-ico" + }, + "time": "2016-09-27T22:00:56+00:00" + }, { "name": "codeigniter4/codeigniter4", "version": "dev-develop", @@ -137,6 +177,59 @@ }, "time": "2021-06-10T06:40:05+00:00" }, + { + "name": "codeigniter4/settings", + "version": "dev-develop", + "source": { + "type": "git", + "url": "https://github.com/codeigniter4/settings.git", + "reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeigniter4/settings/zipball/5d758e5e0a3f9dda9f66303d82ccfbb82e979577", + "reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "codeigniter4/codeigniter4": "dev-develop", + "fakerphp/faker": "^1.9", + "mockery/mockery": "^1.0", + "nexusphp/tachycardia": "^1.0", + "php-coveralls/php-coveralls": "^2.4", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^9.0", + "squizlabs/php_codesniffer": "^3.3" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Sparks\\Settings\\": "src" + }, + "exclude-from-classmap": ["**/Database/Migrations/**"] + }, + "notification-url": "https://packagist.org/downloads/", + "license": ["MIT"], + "authors": [ + { + "name": "Lonnie Ezell", + "email": "lonnieje@gmail.com", + "role": "Developer" + } + ], + "description": "Settings library for CodeIgniter 4", + "homepage": "https://github.com/codeigniter4/settings", + "keywords": ["Settings", "codeigniter", "codeigniter4"], + "support": { + "issues": "https://github.com/codeigniter4/settings/issues", + "source": "https://github.com/codeigniter4/settings/tree/develop" + }, + "time": "2021-08-16T05:07:59+00:00" + }, { "name": "composer/ca-bundle", "version": "1.2.10", @@ -494,16 +587,16 @@ }, { "name": "james-heinrich/getid3", - "version": "2.0.x-dev", + "version": "v2.0.0-beta4", "source": { "type": "git", "url": "https://github.com/JamesHeinrich/getID3.git", - "reference": "ee238d552571c6029898b087d5fc95df826418d6" + "reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/ee238d552571c6029898b087d5fc95df826418d6", - "reference": "ee238d552571c6029898b087d5fc95df826418d6", + "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/5ad79104e937e7d9c8a9141a97e1f063dd1123f8", + "reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8", "shasum": "" }, "require": { @@ -562,9 +655,9 @@ "keywords": ["audio", "codecs", "id3", "metadata", "tags", "video"], "support": { "issues": "https://github.com/JamesHeinrich/getID3/issues", - "source": "https://github.com/JamesHeinrich/getID3/tree/2.0" + "source": "https://github.com/JamesHeinrich/getID3/tree/v2.0.0-beta4" }, - "time": "2021-12-15T17:29:14+00:00" + "time": "2021-10-06T16:23:45+00:00" }, { "name": "kint-php/kint", @@ -745,16 +838,16 @@ }, { "name": "league/commonmark", - "version": "1.6.2", + "version": "1.6.6", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb" + "reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/7d70d2f19c84bcc16275ea47edabee24747352eb", - "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c4228d11e30d7493c6836d20872f9582d8ba6dcf", + "reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf", "shasum": "" }, "require": { @@ -772,7 +865,7 @@ "github/gfm": "0.29.0", "michelf/php-markdown": "~1.4", "mikehaertl/php-shellcommand": "^1.4", - "phpstan/phpstan": "^0.12", + "phpstan/phpstan": "^0.12.90", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2", "scrutinizer/ocular": "^1.5", "symfony/finder": "^4.2" @@ -838,37 +931,40 @@ "type": "tidelift" } ], - "time": "2021-05-12T11:39:41+00:00" + "time": "2021-07-17T17:13:23+00:00" }, { "name": "league/html-to-markdown", - "version": "4.10.0", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/thephpleague/html-to-markdown.git", - "reference": "0868ae7a552e809e5cd8f93ba022071640408e88" + "reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0868ae7a552e809e5cd8f93ba022071640408e88", - "reference": "0868ae7a552e809e5cd8f93ba022071640408e88", + "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/e5600a2c5ce7b7571b16732c7086940f56f7abec", + "reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec", "shasum": "" }, "require": { "ext-dom": "*", "ext-xml": "*", - "php": ">=5.3.3" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "mikehaertl/php-shellcommand": "~1.1.0", - "phpunit/phpunit": "^4.8|^5.7", - "scrutinizer/ocular": "~1.1" + "mikehaertl/php-shellcommand": "^1.1.0", + "phpstan/phpstan": "^0.12.82", + "phpunit/phpunit": "^8.5 || ^9.2", + "scrutinizer/ocular": "^1.6", + "unleashedtech/php-coding-standard": "^2.7", + "vimeo/psalm": "^4.6" }, "bin": ["bin/html-to-markdown"], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.10-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -897,7 +993,7 @@ "keywords": ["html", "markdown"], "support": { "issues": "https://github.com/thephpleague/html-to-markdown/issues", - "source": "https://github.com/thephpleague/html-to-markdown/tree/4.10.0" + "source": "https://github.com/thephpleague/html-to-markdown/tree/5.0.1" }, "funding": [ { @@ -913,11 +1009,11 @@ "type": "github" }, { - "url": "https://www.patreon.com/colinodell", - "type": "patreon" + "url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown", + "type": "tidelift" } ], - "time": "2020-07-01T00:34:03+00:00" + "time": "2021-09-17T20:00:27+00:00" }, { "name": "maxmind-db/reader", @@ -7457,7 +7553,8 @@ "james-heinrich/getid3": 20, "myth/auth": 20, "codeigniter4/codeigniter4": 20, - "michalsn/codeigniter4-uuid": 20 + "michalsn/codeigniter4-uuid": 20, + "codeigniter4/settings": 20 }, "prefer-stable": true, "prefer-lowest": false, @@ -7465,5 +7562,5 @@ "php": "^8.0" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/ecs.php b/ecs.php index 939cae297d..a7d4071516 100644 --- a/ecs.php +++ b/ecs.php @@ -17,7 +17,6 @@ return static function (ContainerConfigurator $containerConfigurator): void { __DIR__ . '/themes', __DIR__ . '/tests', __DIR__ . '/public', - __DIR__ . '/public', ]); $parameters->set(Option::SKIP, [ diff --git a/modules/Admin/Config/Routes.php b/modules/Admin/Config/Routes.php index d259ce905c..edda5e8152 100644 --- a/modules/Admin/Config/Routes.php +++ b/modules/Admin/Config/Routes.php @@ -18,6 +18,21 @@ $routes->group( 'as' => 'admin', ]); + $routes->group('settings', function ($routes): void { + $routes->get('/', 'SettingsController', [ + 'as' => 'settings-general', + 'filter' => 'permission:settings-manage', + ]); + $routes->post('instance', 'SettingsController::attemptInstanceEdit', [ + 'as' => 'settings-instance', + 'filter' => 'permission:settings-manage', + ]); + $routes->get('instance-delete-icon', 'SettingsController::deleteIcon', [ + 'as' => 'settings-instance-delete-icon', + 'filter' => 'permission:settings-manage', + ]); + }); + $routes->group('persons', function ($routes): void { $routes->get('/', 'PersonController', [ 'as' => 'person-list', diff --git a/modules/Admin/Controllers/SettingsController.php b/modules/Admin/Controllers/SettingsController.php new file mode 100644 index 0000000000..1308df71f5 --- /dev/null +++ b/modules/Admin/Controllers/SettingsController.php @@ -0,0 +1,105 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2020 Podlibre + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +namespace Modules\Admin\Controllers; + +use CodeIgniter\HTTP\RedirectResponse; +use PHP_ICO; + +class SettingsController extends BaseController +{ + public function index(): string + { + helper('form'); + return view('settings/general'); + } + + public function attemptInstanceEdit(): RedirectResponse + { + $rules = [ + 'site_icon' => + 'is_image[site_icon]|ext_in[site_icon,png,jpeg]|is_image_squared[site_icon]|min_dims[image,512,512]|permit_empty', + ]; + + if (! $this->validate($rules)) { + return redirect() + ->back() + ->withInput() + ->with('errors', $this->validator->getErrors()); + } + + $siteName = $this->request->getPost('site_name'); + if ($siteName !== service('settings')->get('App.siteName')) { + service('settings')->set('App.siteName', $siteName); + } + + $siteDescription = $this->request->getPost('site_description'); + if ($siteDescription !== service('settings')->get('App.siteDescription')) { + service('settings')->set('App.siteDescription', $siteDescription); + } + + $siteIconFile = $this->request->getFile('site_icon'); + if ($siteIconFile !== null && $siteIconFile->isValid()) { + helper(['filesystem', 'media']); + + // delete site folder in media before repopulating it + delete_files(ROOTPATH . 'public/media/site/'); + + // save original in disk + $originalFilename = save_media($siteIconFile, 'site', 'icon'); + + // convert jpeg image to png if not + if ($siteIconFile->getClientMimeType() !== 'image/png') { + service('image')->withFile(ROOTPATH . 'public/media/' . $originalFilename) + ->convert(IMAGETYPE_JPEG) + ->save(ROOTPATH . 'public/media/site/icon.png'); + } + + // generate random hash to use as a suffix to renew browser cache + $randomHash = substr(bin2hex(random_bytes(18)), 0, 8); + + // generate ico + $ico_lib = new PHP_ICO(); + $ico_lib->add_image(ROOTPATH . 'public/media/site/icon.png', [[32, 32], [64, 64]]); + $ico_lib->save_ico(ROOTPATH . "public/media/site/favicon.{$randomHash}.ico"); + + // resize original to needed sizes + foreach ([64, 180, 192, 512] as $size) { + service('image') + ->withFile(ROOTPATH . 'public/media/site/icon.png') + ->resize($size, $size) + ->save(ROOTPATH . "public/media/site/icon-{$size}.{$randomHash}.png"); + } + + service('settings') + ->set('App.siteIcon', [ + 'ico' => "/media/site/favicon.{$randomHash}.ico", + '64' => "/media/site/icon-64.{$randomHash}.png", + '180' => "/media/site/icon-180.{$randomHash}.png", + '192' => "/media/site/icon-192.{$randomHash}.png", + '512' => "/media/site/icon-512.{$randomHash}.png", + ]); + } + + return redirect()->back(); + } + + public function deleteIcon(): RedirectResponse + { + helper('filesystem'); + // delete site folder in media + delete_files(ROOTPATH . 'public/media/site/'); + + service('settings') + ->forget('App.siteIcon'); + + return redirect()->back(); + } +} diff --git a/modules/Admin/Language/en/AdminNavigation.php b/modules/Admin/Language/en/AdminNavigation.php index 68cbefb3eb..c2e8e4b696 100644 --- a/modules/Admin/Language/en/AdminNavigation.php +++ b/modules/Admin/Language/en/AdminNavigation.php @@ -29,6 +29,8 @@ return [ 'pages' => 'Pages', 'page-list' => 'All pages', 'page-create' => 'New Page', + 'settings' => 'Settings', + 'settings-general' => 'General', 'account' => [ 'my-account' => 'My account', 'change-password' => 'Change password', diff --git a/modules/Admin/Language/en/Breadcrumb.php b/modules/Admin/Language/en/Breadcrumb.php index 9a1ef1c2f9..63564f79d9 100644 --- a/modules/Admin/Language/en/Breadcrumb.php +++ b/modules/Admin/Language/en/Breadcrumb.php @@ -16,6 +16,7 @@ return [ 'episodes' => 'episodes', 'contributors' => 'contributors', 'pages' => 'pages', + 'settings' => 'settings', 'add' => 'add', 'new' => 'new', 'edit' => 'edit', diff --git a/modules/Admin/Language/en/Settings.php b/modules/Admin/Language/en/Settings.php new file mode 100644 index 0000000000..8864c87fdb --- /dev/null +++ b/modules/Admin/Language/en/Settings.php @@ -0,0 +1,23 @@ +<?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 [ + 'title' => 'General settings', + 'form' => [ + 'site_section_title' => 'Instance', + 'site_icon' => 'Site icon', + 'site_icon_delete' => 'Delete site icon', + 'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.', + 'site_icon_helper' => 'Icon must be squared with at least 512px wide and tall.', + 'site_name' => 'Site name', + 'site_description' => 'Site description', + 'submit' => 'Save', + ], +]; diff --git a/modules/Admin/Language/fr/AdminNavigation.php b/modules/Admin/Language/fr/AdminNavigation.php index 357b64ffab..b85b1a3025 100644 --- a/modules/Admin/Language/fr/AdminNavigation.php +++ b/modules/Admin/Language/fr/AdminNavigation.php @@ -28,6 +28,8 @@ return [ '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', diff --git a/modules/Admin/Language/fr/Settings.php b/modules/Admin/Language/fr/Settings.php new file mode 100644 index 0000000000..e68c87c7a2 --- /dev/null +++ b/modules/Admin/Language/fr/Settings.php @@ -0,0 +1,24 @@ +<?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 [ + 'title' => 'Paramètres généraux', + 'form' => [ + 'site_section_title' => 'Instance', + 'site_section_subtitle' => 'configuration de l’instance', + '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 et avoir au moins 512px de largeur et de hauteur.', + 'site_name' => 'Titre du site', + 'site_description' => 'Description du site', + 'submit' => 'Save', + ], +]; diff --git a/modules/Install/Controllers/InstallController.php b/modules/Install/Controllers/InstallController.php index 59bad8c901..5a65ce4475 100644 --- a/modules/Install/Controllers/InstallController.php +++ b/modules/Install/Controllers/InstallController.php @@ -243,6 +243,8 @@ class InstallController extends Controller { $migrations = Services::migrations(); + $migrations->setNamespace('Sparks\Settings') + ->latest(); $migrations->setNamespace('Myth\Auth') ->latest(); $migrations->setNamespace('Modules\Fediverse') diff --git a/public/favicon.ico b/public/favicon.ico index b844d1d06dc8c533874fdb40bdb0701700dda75f..9bf9b97aa31acf5e8dc1c93087eaa79b80d60396 100644 GIT binary patch literal 21238 zcmZQzU}RuoP*4ET3Jfa*7#P$T7#JKJAbbrc28MG23=A3!3=9e&aR!Ju0}jwOh2j4w z9u0%hG%%V5M$^D(8UUq%dFyQcAG$jA|HY>}|6hK#mm&-@<It5U|L3l?BBGvQ{J-aX z`~Sy3p8bFF^Ep*9$jsemoAA0}<Do37+KJ5%>kp)2bwk$-uK)Kw--6qJ<IU;+C+{r% z|LEJJ{|~<2`+xAt<o~zcorB9`GaDp!_2rTON3YNR|M1(x{|~=C_<!u?y#IGTT!HJm z`|0}s&gmQ&ZdkCv39bfY&bAZfU^VSing6#>WdgHzooPT(15$^MHy_CdtA*%e2DA5F z=t9vqf4wbO9F*2zc-8JG6g4pWVe%k)*O^8XHRyJO_%QoH>R}k&{*^n!FzjEl#S_Ks z8*fhj@1Ds6SJyLJ;Qy_6=TX#v>_f+(@b8?#3D?&*M+7DOLFyN6c8ANu+}Jxu2prcS zc^JO(eE<J7d*lDF-Iw?uWG+mc5Pj*{?*D7{#QtBmKl%Ul*T+%Z3`$QRyI}Sr(|gXf zp{ONf4>|IC&v#(>9p(m5xSf5lj%IE+_i)pHP(Fj%hmG!-#`+&r4qSV6<p1LzPbqc_ zsNA{s>e&BHNAmu6Ok>08cWiC}<sp!JD8V2zu$et7Hd@z@rh(BkfMZyIZo;5(3I_%T zhKA8`3X<xE(Y!mFcSqB}Xc`zz1EXnRG!2ZVfzdQDng&MGz-Ss6O#`E8U^ESkrh(Bk zFq#HN)4*sN7)=ACX<#I#fvHQ>{;%7g^ncH}*8c~uO!|N5%H#pXAUA;AvUXp>|0#== zX*SkBf4$xR^N+VsJa0|T+&-~-Ky%{f9&Y?UcdaGW!T~f#4qE2{GMiX;4756sTX&yr z{@*^8g`#i(`5m-YXrTQ=uKh=E%=u5rIt9?05_0VxEc$kyt|KcA%v)zoll5}+4j0f` zn^~)jNe+W^k2d2h>p*7W^T)kUH~v5R{sgCfe0s6T-T!hMyygy@97qi09#EbKv9aOP z_g0bQ|7puK@w$Ec$;$t8R-64lczF_h4I0RP(0ZipCo2E<&Jq4k&AhYWVEX?_3+4as zIp2n|R_^B8GvIo7>QeRppuCRF?;tUd+a@nkBsvU0YpOu{aN$V{<xtG(nZ^IV3u$d0 zs9iL3g+AUe#AP<RI4B)~)(C>kgkjM7K@f)VLG;3nsOv1z&B3)k6r>j&AGtmYr`thm zNzv6~<AdrBbT^R0zy9VVN?2pF3nbP*PaLP4LH2^uDo7nM7+>DM|M?bC?g6dI1KCR{ zrk4LnDFZG%-i9|UCoPmE7zQ&}8sIg9*l+=-|5^M5?L%K@jBY+?{U<ST4^ngT&N94i z-+rQkpnE`VMszoj%LkQzAa~)z_{u+!y~l6PC+KFF`GnR(gVuk~T4{*WyagK^|3Cgg zz4{MS=79QLF!!O;%eDm&Y^&@zRfE&L=;kfj<cc@`LE#B<)5=}pDD6v7nFs0{KKOc{ zpni}Uq+rlm`=wib{<lqGg!==u-hR{J-2achKO$(~!i~;wedzv0=Y#xl=fh=!W`f)g zQU}T}r|z!!5849&5~C#st(6D$NkHWpC=Q6R3lw&s@)+Hp`1qi3CC2Qbpa#^Q!RJ?O za-i_K^5OtdX<#si!PS?C|94JjCpzsThsBg7D*x|(yf$RR0F*zbE!8B;@33%~v0MkG z%{`do8rf~2JWo!)59V)Vx^J%Ne^8qk)Q>>6W3aN1-&**8!hA`J;vL!lF!uCi+W$f0 zN>^SSB&yD#SNJ^o{`mjZmxuoEJ>UKx)b512m$oz`c+U@L-_JnfwkeQ(bhP#F=zPa$ z_>QK5(KIlc21e7sXc`zz1EXnRG!2ZVfzdQDng&MGz-Ss6O#?$S4bbgCf>DbGWe5NO D0pgQO literal 16958 zcmZQzU}RuqaBu+83Je-f3=Con3=A3!3=9qo3=9nn5OD?&aAIH(=7wMp7lhlUF#I3I zqhT<b21e7sXc`zz1EXnRG!2ZVfzdQDng&MGz-Ss6O#`E8U^ESkrh(BkFq#HN)4*sN z7)=ACX<%fhftf4x{%<~#|Nro{Y5z~&S@!?zgLMOnPu*Sd|LFBu|F<41{y%56>HoGV zj5L|gn7`is|D|WU|3CTpd{E=7FAx1+vc;2XVbDI6`Tw4CErZ(6*y7~y)v5oxW^hs% z4vhan=3p~_D2Sc8zxsd2G*+_1V9T+hAs6rH@v`qiCt3cVwp9K9;~!6ky#GPrF>kFE z$zgEh`pjYBcaZ<jJ={Q&|9fW({D1uY@v!kfC=8}7Rwg<OmTmJR==W={j{FDZtp{K4 zVyM0ReDD9wNAoenLGB<2?>*oC|MvR}Sj>C&|M;y1|8KrKi$xB#o?d?-m1zHOKUqQ0 zyp_Ac!RB>NXa7HMo%R1!yCVKC-x2hG%3>w3IH;X`>h5xa<`4>x^N%)z%>&iLAbU0( z$^eJ$iXB1!`{#*)<<{(tBWTaT%M-wALGB`i4_=-~&^%;+;xcdD{$zsY5c2=l<0S;$ zJ#m2yL3==Pfy<rf;>7rW@*+io?pm=Un4r4|`5zSD=<Y-3gX(xf=A6E_lAwEG=I%b* zOwirSwg(V2j~ea91DARU+B1E*HbM6ux;mAhIWYgP*&9pHybDjZ{|Dtsm>zVxZ?5S7 zd!KI-G>1^Ufz0TgBZ$}SpmLayIhzjW;57r;{gW3d5an)A++Yg>Q2lxS(I%qIAmnb4 zJgA@9Ih_rw`<HI@`TykSGlF)_SgwOrKeE4(*`RV4WH%vv`PrWTt9D2JpRru~|EyI; z|2H1W`hWZVMS|`jWG=e=rDuEoFWThxzjFo$*dJ4usQ%w`uJ!-pA5RI|1*(sc{YDHM zWEZ*{1`Geu_eTW%jO<oW8X?Bd=xUDNoKKQH$aW4E_Q^X-!083uZ^ZC>X7m3Cwetpx zUr2SwwO2>~6Dm6ig~NpT68}MYk5sz{TK(nc`~FXuFG+UXBZmv9%-MCO@jt2gZXm({ z<VKKNL2gF&12xza=S%$uwMQ>J+4le8*ZYH}Yyi0h<R*~YKyIXlUx_gT)b8w=#rJ<8 zF~|+XxOG&`$ey<tjsMa3A58<JX<#%BjHZFnG%%V5M$^D(8W>FjqiJ9?4UDFNk(>rV LX8?@iksAU4@Y2ij diff --git a/public/icon-180.png b/public/icon-180.png new file mode 100644 index 0000000000000000000000000000000000000000..937c4c6c80ad0926a8fbfc1783d26c76e0698072 GIT binary patch literal 17522 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 Uo8|nIfq{X+)78&qol`;+0RI5sUH||9 literal 0 HcmV?d00001 diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..7864f7e9495a68e5e5bc6958d602bab2c4733a2c GIT binary patch literal 5913 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 literal 0 HcmV?d00001 diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..9998e36ae442c3aa2a55834aa093163d5dd05dbd GIT binary patch literal 7340 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 literal 0 HcmV?d00001 diff --git a/public/icon-64.png b/public/icon-64.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8d2cf1cc1cb9704de282006a76a1ce86568be7 GIT binary patch literal 738 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4rT@hhPm4t-!L#RS_k-qxH3#>W1ZH)H>*c# z{=|~wTem&AaR2MW=Rcot%;;=9v+L3KM-uZV?0I%+-}B3o^C$4n?m6=6+R<0n1n2b5 zzj=Jgos({x7Wr&ly7|%hJ<l#j?p~$6e1_4gSy_iRUVMLBb;;D$b9<itc)a)dWranP zdoLYep4u)jyLZ#0^ULm>WSidk?B^4m<uhXUuG#+Ng6Q17o1gD>Uf7p&cvJJ)-2vN| zwVd0dy?pxAtA{3DKB%~8a`2878HYBkymwk@@s#BK>tq&8Tz>ad#mVjAyH>JK@3dYw zFJjlKpdHKek8Tdyu|jNKf85?R6D}Y0+qUfP*9YzA_g;8^d%>;aXW!jSJ+S`q_s7bM zr_8*5WW&RA>Px3R`SI9l?YyF6TNtObO}%<}_5CxPGrH{8&)@y*(xI1EJ+~~;TQM{L z$mVI+4zGJ~cE#OOv#uX4KDO0#^_+F9=7PePv%n*=n1O-s2naJy)#j6CU|{t1ba4!c zXni{+Jou1<h?}|4jfNEw47-&ak2t;QVii4l&-%vh|Nq5LoQiptW<KdnbAGklp(i=# zzE3#m(BZT&;E!-rGk4V78_Rz)Uzyqv|K0MLo57Q~a86d<jrly)XC-~l*4!7G_);@B z_c7b8r&V6oZ)&eZx84srV<xcv=ec$7=H0VfZY5*t@&ACr9kl}ckZP^WO~0>fxUt;5 zPQEwQp=VK};e^L&p*|@;?YQ&LG8uQWEpzZ|p81e{Qh^b78XxbO<`{;}C-|Q{aADs3 z#AE|cTC4nphbf{ya=dFAW7MTv&#pb?Gf%!lc=H79y!R7g4XQH|<Wr7VCD?Z=-4Cv+ zII?c$V_|{i849IpZ0qJc=6~q4Z~qb7ox7&V?bygWA^PUMP2ZP<Ond#lWxrYQk8iI6 z_dWm3#or(Id3k#KoR6P=O{*(^`1ted-Cx|-2WW_J9pyhCVEfnX)VBEy3=9mOu6{1- HoD!M<ysCpf literal 0 HcmV?d00001 diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3c182ad441f3c993ef0d680db2293ebe0018bcb3 GIT binary patch literal 7027 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 literal 0 HcmV?d00001 diff --git a/themes/cp_admin/_layout.php b/themes/cp_admin/_layout.php index 3b673615ab..17274d51df 100644 --- a/themes/cp_admin/_layout.php +++ b/themes/cp_admin/_layout.php @@ -7,7 +7,10 @@ <title><?= $this->renderSection('title') ?> | Castopod Admin</title> <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <?= service('vite') ->asset('styles/index.css', 'css') ?> diff --git a/themes/cp_admin/_sidebar.php b/themes/cp_admin/_sidebar.php index 0a1a7f410a..dd8cb12a4d 100644 --- a/themes/cp_admin/_sidebar.php +++ b/themes/cp_admin/_sidebar.php @@ -22,6 +22,10 @@ $navigation = [ 'items' => ['page-list', 'page-create'], ], + 'settings' => [ + 'icon' => 'settings', + 'items' => ['settings-general'], + ], ]; ?> <nav class="flex flex-col flex-1 py-4 overflow-y-auto gap-y-4"> diff --git a/themes/cp_admin/person/edit.php b/themes/cp_admin/person/edit.php index 49c2ca484d..7ce8966e79 100644 --- a/themes/cp_admin/person/edit.php +++ b/themes/cp_admin/person/edit.php @@ -35,6 +35,7 @@ label="<?= lang('Person.form.unique_name') ?>" hint="<?= lang('Person.form.unique_name_hint') ?>" required="true" /> + <Forms.Field name="information_url" label="<?= lang('Person.form.information_url') ?>" diff --git a/themes/cp_admin/settings/general.php b/themes/cp_admin/settings/general.php new file mode 100644 index 0000000000..f48bc58136 --- /dev/null +++ b/themes/cp_admin/settings/general.php @@ -0,0 +1,59 @@ +<?= $this->extend('_layout') ?> + +<?= $this->section('title') ?> +<?= lang('Settings.title') ?> +<?= $this->endSection() ?> + +<?= $this->section('pageTitle') ?> +<?= lang('Settings.title') ?> +<?= $this->endSection() ?> + +<?= $this->section('content') ?> + +<form action="<?= route_to('settings-instance') ?>" method="POST" class="flex flex-col max-w-sm gap-y-4" enctype="multipart/form-data"> +<?= csrf_field() ?> + +<Forms.Section + title="<?= lang('Settings.form.site_section_title') ?>"> + + <Forms.Field + name="site_name" + label="<?= lang('Settings.form.site_name') ?>" + value="<?= service('settings') + ->get('App.siteName') ?>" + required="true" /> + + <Forms.Field + as="Textarea" + name="site_description" + label="<?= lang('Settings.form.site_description') ?>" + value="<?= service('settings') + ->get('App.siteDescription') ?>" + required="true" + rows="4" /> + + <div class="flex items-center"> + <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') ?>" + accept=".png,.jpeg" + 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-white bg-red-600 border-2 border-black rounded-full hover:bg-red-800 -top-3 -right-3 focus:ring-castopod" title="<?= lang('Settings.form.site_icon_delete') ?>"><?= 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> + +</Forms.Section> + +</form> + +<?= $this->endSection() ?> diff --git a/themes/cp_app/_layout.php b/themes/cp_app/_layout.php index eda77ca644..54afb9f285 100644 --- a/themes/cp_app/_layout.php +++ b/themes/cp_app/_layout.php @@ -6,9 +6,20 @@ <head> <meta charset="UTF-8"/> <title><?= $this->renderSection('title') ?></title> - <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/> + <meta name="description" content="<?= service('settings') + ->get('App.siteDescription') ?>"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> + + <meta property="og:title" content="<?= service('settings') + ->get('App.siteName') ?>" /> + <meta property="og:description" content="<?= service('settings') + ->get('App.siteDescription') ?>" /> + <meta property="og:site_name" content="<?= service('settings') + ->get('App.siteName') ?>" /> <?= service('vite') ->asset('styles/index.css', 'css') ?> diff --git a/themes/cp_app/embed.php b/themes/cp_app/embed.php index 2817de36ac..612a5f1f03 100644 --- a/themes/cp_app/embed.php +++ b/themes/cp_app/embed.php @@ -8,7 +8,10 @@ <meta name="description" content="<?= htmlspecialchars( $episode->description, ) ?>" /> - <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <link rel="canonical" href="<?= $episode->link ?>" /> <?= service('vite') ->asset('styles/index.css', 'css') ?> diff --git a/themes/cp_app/episode/_layout.php b/themes/cp_app/episode/_layout.php index 8eb6efd872..813c198387 100644 --- a/themes/cp_app/episode/_layout.php +++ b/themes/cp_app/episode/_layout.php @@ -7,7 +7,10 @@ <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <?= $this->renderSection('meta-tags') ?> <?php if ($podcast->payment_pointer): ?> diff --git a/themes/cp_app/home.php b/themes/cp_app/home.php index 310f50539e..0852e85c05 100644 --- a/themes/cp_app/home.php +++ b/themes/cp_app/home.php @@ -5,10 +5,23 @@ <head> <meta charset="UTF-8"/> - <title>Castopod</title> - <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/> + <title><?= service('settings') + ->get('App.siteName') ?></title> + <meta name="description" content="<?= service('settings') + ->get('App.siteDescription') ?>"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> + + <meta property="og:title" content="<?= service('settings') + ->get('App.siteName') ?>" /> + <meta property="og:description" content="<?= service('settings') + ->get('App.siteDescription') ?>" /> + <meta property="og:site_name" content="<?= service('settings') + ->get('App.siteName') ?>" /> + <?= service('vite') ->asset('styles/index.css', 'css') ?> <?= service('vite') diff --git a/themes/cp_app/map.php b/themes/cp_app/map.php index e59fcd0168..2838dcea8d 100644 --- a/themes/cp_app/map.php +++ b/themes/cp_app/map.php @@ -8,7 +8,10 @@ <title><?= lang('Page.map') ?></title> <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <?= service('vite') ->asset('styles/index.css', 'css') ?> <?= service('vite') diff --git a/themes/cp_app/page.php b/themes/cp_app/page.php index b8c0f8e7f4..84399887f1 100644 --- a/themes/cp_app/page.php +++ b/themes/cp_app/page.php @@ -7,7 +7,10 @@ <meta charset="UTF-8"/> <title><?= $page->title ?></title> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <?= service('vite') ->asset('styles/index.css', 'css') ?> <?= service('vite') diff --git a/themes/cp_app/podcast/_layout.php b/themes/cp_app/podcast/_layout.php index 487a58abcf..8a9c9eea16 100644 --- a/themes/cp_app/podcast/_layout.php +++ b/themes/cp_app/podcast/_layout.php @@ -7,7 +7,10 @@ <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <?= $this->renderSection('meta-tags') ?> <?php if ($podcast->payment_pointer): ?> diff --git a/themes/cp_app/podcast/about.php b/themes/cp_app/podcast/about.php index 7383c93cd0..1c80116ca4 100644 --- a/themes/cp_app/podcast/about.php +++ b/themes/cp_app/podcast/about.php @@ -9,7 +9,10 @@ <meta name="description" content="<?= htmlspecialchars( $podcast->description, ) ?>" /> -<link rel="shortcut icon" type="image/png" href="/favicon.ico" /> +<link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> +<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> +<link rel="manifest" href="<?= route_to('webmanifest') ?>"> <link rel="canonical" href="<?= current_url() ?>" /> <meta property="og:title" content="<?= $podcast->title ?>" /> <meta property="og:description" content="<?= $podcast->description ?>" /> diff --git a/themes/cp_app/podcast/activity.php b/themes/cp_app/podcast/activity.php index f291f25794..3743d8859b 100644 --- a/themes/cp_app/podcast/activity.php +++ b/themes/cp_app/podcast/activity.php @@ -7,7 +7,10 @@ <meta name="description" content="<?= htmlspecialchars( $podcast->description, ) ?>" /> -<link rel="shortcut icon" type="image/png" href="/favicon.ico" /> +<link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> +<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> +<link rel="manifest" href="<?= route_to('webmanifest') ?>"> <link rel="canonical" href="<?= current_url() ?>" /> <meta property="og:title" content="<?= $podcast->title ?>" /> <meta property="og:description" content="<?= $podcast->description ?>" /> diff --git a/themes/cp_app/podcast/episodes.php b/themes/cp_app/podcast/episodes.php index c5a97c9aee..8b6bae0fe4 100644 --- a/themes/cp_app/podcast/episodes.php +++ b/themes/cp_app/podcast/episodes.php @@ -7,7 +7,10 @@ <meta name="description" content="<?= htmlspecialchars( $podcast->description, ) ?>" /> -<link rel="shortcut icon" type="image/png" href="/favicon.ico" /> +<link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> +<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> +<link rel="manifest" href="<?= route_to('webmanifest') ?>"> <link rel="canonical" href="<?= current_url() ?>" /> <meta property="og:title" content="<?= $podcast->title ?>" /> <meta property="og:description" content="<?= $podcast->description ?>" /> diff --git a/themes/cp_app/podcast/follow.php b/themes/cp_app/podcast/follow.php index 473980cf75..abd8888d77 100644 --- a/themes/cp_app/podcast/follow.php +++ b/themes/cp_app/podcast/follow.php @@ -7,8 +7,10 @@ <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> - <?= service('vite')->asset('styles/index.css', 'css') ?> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <title><?= lang('Podcast.followTitle', [ 'actorDisplayName' => $actor->display_name, diff --git a/themes/cp_app/post/remote_action.php b/themes/cp_app/post/remote_action.php index 3a885e9ee1..6914f04bee 100644 --- a/themes/cp_app/post/remote_action.php +++ b/themes/cp_app/post/remote_action.php @@ -5,7 +5,10 @@ <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <title><?= lang('Fediverse.' . $action . '.title', [ 'actorDisplayName' => $post->actor->display_name, diff --git a/themes/cp_auth/_layout.php b/themes/cp_auth/_layout.php index b22e49856d..9ac33873f9 100644 --- a/themes/cp_auth/_layout.php +++ b/themes/cp_auth/_layout.php @@ -7,7 +7,7 @@ <title>Castopod Auth</title> <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="/favicon.ico" /> <?= service('vite') ->asset('styles/index.css', 'css') ?> </head> diff --git a/themes/cp_install/_layout.php b/themes/cp_install/_layout.php index a3ed84c476..affa0827c6 100644 --- a/themes/cp_install/_layout.php +++ b/themes/cp_install/_layout.php @@ -6,7 +6,10 @@ <title>Castopod</title> <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <link rel="shortcut icon" type="image/png" href="/favicon.ico" /> + <link rel="icon" type="image/x-icon" href="<?= service('settings') + ->get('App.siteIcon')['ico'] ?>" /> + <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>"> + <link rel="manifest" href="<?= route_to('webmanifest') ?>"> <?= service('vite') ->asset('styles/index.css', 'css') ?> <?= service('vite') -- GitLab