From 5c56f3e6f00a61af2ccf50811c155c325f2b10fa Mon Sep 17 00:00:00 2001 From: Yassine Doghri 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 47f4c373..4ed935bc 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 df445db0..4d2227c0 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 + */ + 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 45eff6b9..7d2ca19f 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 00000000..dd320e44 --- /dev/null +++ b/app/Controllers/WebmanifestController.php @@ -0,0 +1,45 @@ + 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 2fb6fb6a..eb9af6a7 100644 --- a/app/Database/Seeds/AuthSeeder.php +++ b/app/Database/Seeds/AuthSeeder.php @@ -40,6 +40,18 @@ class AuthSeeder extends Seeder * @var 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 312af42a..b9a1c65b 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 3ca24a4f..b7dffcaf 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 03baaec3..82b1287a 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 939cae29..a7d40715 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 d259ce90..edda5e81 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 00000000..1308df71 --- /dev/null +++ b/modules/Admin/Controllers/SettingsController.php @@ -0,0 +1,105 @@ + + '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 68cbefb3..c2e8e4b6 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 9a1ef1c2..63564f79 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 00000000..8864c87f --- /dev/null +++ b/modules/Admin/Language/en/Settings.php @@ -0,0 +1,23 @@ + '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 357b64ff..b85b1a30 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 00000000..e68c87c7 --- /dev/null +++ b/modules/Admin/Language/fr/Settings.php @@ -0,0 +1,24 @@ + '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 59bad8c9..5a65ce44 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 zcmeHPTWl0n7@mUSB_=nB4Z*p>G&gH+& zcP_K@ohnL(vP{X$R79SsRIXH%)rz8IWi8&XS+6JoQMN{ui6)9DR@;dz;$OB~Ax<0v z#sFi0F~ArA21;t5rJfNF{dl^Sh8H>$N|4bLbkp9Nr=wVBGN@xHhvxrYpi}>xNos=3 z_7k5=ZD{EED5*Ll`A~QGgNQclD7clT|D4eEkDVW&{>cgoUk=mkrD^I8=F!CO0lhww zY?O_h_0!SN9-6y6C(x_?fAVOuw<8Rex3M z>sRS7Kk$l4_SpG;`m*pgz1_||D@FW=Ol>0RNBp-J+@kl}ReYx@{^(QI^s-*B+4)uR z9qO|-$_$=4MEg76rkbvI)#qxglU@I`&`$e1-lEz=?^Ed4UX#th6Le{Mjd@2P+tgO3 zBi_2sq1=eNVF%)NVzxGAHU#Dx3FFM@v-LVR|3<<*FnZ1}=AqLG+k$y#^xQFO^nXIR z`75Nlt+rt7!Jb4CWLV|$J+JeO0mc9@5b;NWYgmZiDY8V`DiVIru=``YGF}-2i~+^~ zV}LQh7+?%A1{ed30mcAhfHA-rU<@z@7z2y}#sFi0F~At`l&==wzu%*dz!!o$;SwB_ zyz81^18k}3dWYQKKA5s^vZZy;)6o2Zguh$I`+Yx}e)uLHm}?N6pr?`+2Ye$3&m$Gw zp=f-Hr_CZKX`A5J+>lTl;5)cN@z}5w`WziA7BPsQrvOgLQt%@Y8(Igp#D#&9+Go-V z^L8-;*QTiYiI`&$2shb2dnf+R^u;j>UpZyl-_BOM@|nMWRylWe^{_`aKMhP*$K-#$ zZ>`k!mi|pt{QZ;EJ?zpsXwVNnQcK?^!2?@G$s9ZN-5-+6d%xgtW}CQj)OMHmUdLD#Ry`(_5v~6!{>AumdS+Ihu~k0! zpH4Eg`u<6u)b^IXPaS1hxxrR@V!6lsr`cwg%jQ4m>K!k2l%dIX;zNV~T~zhBt-O8p zFNpOhdFvnM9K3gF_E~dZ^J~)e5B?uKzS*|FRbE-+OVZ~Ld9bOf?G4lZ5_2Bj4QDUS zIQEa_`J*kk_7y+8DtyS${Q%#-@yN$wuMu|C=WTdV?`QSbdJjJ)FAO`%T(oOgyd(JN z_*5m~3_z@Y#o8WRdAyTgJ~N(ckjX*pV&zC9t}>bFREPbH^%*6_Af5_;}N|F!GgzDLAaw{2ox=#Fa5xmGa=Uzr!@n0mxJXAWWCso9&_ zJVQP6gL6OEJ7v2U&(WpUU;gc%51B?O20AqkLz!+c*Fa{U{i~+_#dSbxt M{{nFN|04qb0s-QaO8@`> literal 16958 zcmeHPOH30{6dhvx#l%mHM2!p77)dlPOx)-~;=;tl7^4eyp&Mgjj0uUlaH;WwHJ}hE zl#i4k(DD(Ge}E#CUqA|#1_;Wx)Hbrvg(2wb`fkaPu}rMPQpM zU(wb(Zidd0EU4|e4>_eL#Iua3|MEP;SaBK#-A&;7?Fs8P^vwzdHRqNs2MPLh(A@tt ztTn6Eq^z}`a!i)6vLFb^R>t4iam+RAF*9E0Nz3?#1{BlLS ze#}GeyOROupkpL+RcJ^3{nM2J=}*eu4m0yJt42TOAnolz%{eHlyFh9mp6vjj+;mvDi;IJYA+tn!x*R1dfS^@vxxONH`;rw%yNT_ z)8Hejyz&n>NgPUlZTAC`cS_zqG7i?lA5Y(YE&5aQ_mg<$hRY-` zNmSf%6I+#Sp$uJ!u`C7#~PS!_l%PiMP zJiDtN@SgOC_3F(onD{wL;!t%%jHH|$e&b+#9ET~Ks`k78#8B!;&5t4RFdo)MEeAM% z4mhhcVNksBIDXF5Wo%I8Us!uy#Br0c45p*1*DG}^_i^0S!p-4shLWahU=SY6Dmf1C zt#`y+^-0sUTJYs_21T6wsR7aS6w%btlf>Q^!r&c{k^TJ|xP96Q{$&Ut4* z+|VOhH2a>@J!%XnPPpX>`Sgqx1f?Bwk(j*=aGe*9y0mZ_p6w*ZPT!jQzE3vp7T^0c zM_djZo)$?gdGt2iODb0rmiUfIYw-U=Oed V*aPeV_CTb2K>i&7-mc9I`~mRN%klsK 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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 LT(?2nCFXwsK6V1% 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/themes/cp_admin/_layout.php b/themes/cp_admin/_layout.php index 3b673615..17274d51 100644 --- a/themes/cp_admin/_layout.php +++ b/themes/cp_admin/_layout.php @@ -7,7 +7,10 @@ <?= $this->renderSection('title') ?> | Castopod Admin - + + + asset('styles/index.css', 'css') ?> diff --git a/themes/cp_admin/_sidebar.php b/themes/cp_admin/_sidebar.php index 0a1a7f41..dd8cb12a 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'], + ], ]; ?>