fix(routes): overwrite RouteCollection to include all routes + update js and php dependencies

This commit is contained in:
Yassine Doghri 2023-08-21 16:13:03 +00:00
parent ef04ce5c41
commit b4f1b916bf
27 changed files with 11067 additions and 13812 deletions

View File

@ -2,7 +2,6 @@
declare(strict_types=1); declare(strict_types=1);
use Config\Services;
use Config\View; use Config\View;
use ViewThemes\Theme; use ViewThemes\Theme;
@ -49,42 +48,3 @@ if (! function_exists('view')) {
->render($name, $options, $saveData); ->render($name, $options, $saveData);
} }
} }
if (! function_exists('lang')) {
/**
* A convenience method to translate a string or array of them and format the result with the intl extension's
* MessageFormatter.
*
* Overwritten to include an escape parameter (escaped by default).
*
* @param array<int|string, string> $args
*
* TODO: remove, and escape args when necessary
*
* @return string|string[]
*/
function lang(string $line, array $args = [], ?string $locale = null, bool $escape = true): string | array
{
$language = Services::language();
// Get active locale
$activeLocale = $language->getLocale();
if ($locale && $locale !== $activeLocale) {
$language->setLocale($locale);
}
$line = $language->getLine($line, $args);
if (! $locale) {
return $escape ? esc($line) : $line;
}
if ($locale === $activeLocale) {
return $escape ? esc($line) : $line;
}
// Reset to active locale
$language->setLocale($activeLocale);
return $escape ? esc($line) : $line;
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Config; namespace Config;
use App\Filters\AllowCorsFilter;
use CodeIgniter\Config\BaseConfig; use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Filters\CSRF; use CodeIgniter\Filters\CSRF;
use CodeIgniter\Filters\DebugToolbar; use CodeIgniter\Filters\DebugToolbar;
@ -25,6 +26,7 @@ class Filters extends BaseConfig
'honeypot' => Honeypot::class, 'honeypot' => Honeypot::class,
'invalidchars' => InvalidChars::class, 'invalidchars' => InvalidChars::class,
'secureheaders' => SecureHeaders::class, 'secureheaders' => SecureHeaders::class,
'allow-cors' => AllowCorsFilter::class,
]; ];
/** /**

View File

@ -6,6 +6,7 @@ namespace Config;
use App\Libraries\Breadcrumb; use App\Libraries\Breadcrumb;
use App\Libraries\Negotiate; use App\Libraries\Negotiate;
use App\Libraries\RouteCollection;
use App\Libraries\Router; use App\Libraries\Router;
use CodeIgniter\Config\BaseService; use CodeIgniter\Config\BaseService;
use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\Request;
@ -43,6 +44,21 @@ class Services extends BaseService
return new Router($routes, $request); return new Router($routes, $request);
} }
/**
* The Routes service is a class that allows for easily building
* a collection of routes.
*
* @return RouteCollection
*/
public static function routes(bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('routes');
}
return new RouteCollection(self::locator(), config('Modules'));
}
/** /**
* The Negotiate class provides the content negotiation features for working the request to determine correct * The Negotiate class provides the content negotiation features for working the request to determine correct
* language, encoding, charset, and more. * language, encoding, charset, and more.

View File

@ -0,0 +1,137 @@
<?php
declare(strict_types=1);
/**
* This file extends the Router class from the CodeIgniter 4 framework.
*
* It introduces the alternate-content option for a route.
*
* @copyright 2023 Ad Aures
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Libraries;
use CodeIgniter\Router\RouteCollection as CodeIgniterRouteCollection;
class RouteCollection extends CodeIgniterRouteCollection
{
/**
* Does the heavy lifting of creating an actual route. You must specify
* the request method(s) that this route will work for. They can be separated
* by a pipe character "|" if there is more than one.
*
* @param array|Closure|string $to
*/
protected function create(string $verb, string $from, $to, ?array $options = null)
{
$overwrite = false;
$prefix = $this->group === null ? '' : $this->group . '/';
$from = esc(strip_tags($prefix . $from));
// While we want to add a route within a group of '/',
// it doesn't work with matching, so remove them...
if ($from !== '/') {
$from = trim($from, '/');
}
// When redirecting to named route, $to is an array like `['zombies' => '\Zombies::index']`.
if (is_array($to) && count($to) === 2) {
$to = $this->processArrayCallableSyntax($from, $to);
}
$options = array_merge($this->currentOptions ?? [], $options ?? []);
// Route priority detect
if (isset($options['priority'])) {
$options['priority'] = abs((int) $options['priority']);
if ($options['priority'] > 0) {
$this->prioritizeDetected = true;
}
}
// Hostname limiting?
if (! empty($options['hostname'])) {
// @todo determine if there's a way to whitelist hosts?
if (! $this->checkHostname($options['hostname'])) {
return;
}
$overwrite = true;
}
// Limiting to subdomains?
elseif (! empty($options['subdomain'])) {
// If we don't match the current subdomain, then
// we don't need to add the route.
if (! $this->checkSubdomains($options['subdomain'])) {
return;
}
$overwrite = true;
}
// Are we offsetting the binds?
// If so, take care of them here in one
// fell swoop.
if (isset($options['offset']) && is_string($to)) {
// Get a constant string to work with.
$to = preg_replace('/(\$\d+)/', '$X', $to);
for ($i = (int) $options['offset'] + 1; $i < (int) $options['offset'] + 7; $i++) {
$to = preg_replace_callback('/\$X/', static fn ($m) => '$' . $i, $to, 1);
}
}
// Replace our regex pattern placeholders with the actual thing
// so that the Router doesn't need to know about any of this.
foreach ($this->placeholders as $tag => $pattern) {
$from = str_ireplace(':' . $tag, $pattern, $from);
}
// If is redirect, No processing
if (! isset($options['redirect']) && is_string($to)) {
// If no namespace found, add the default namespace
if (strpos($to, '\\') === false || strpos($to, '\\') > 0) {
$namespace = $options['namespace'] ?? $this->defaultNamespace;
$to = trim($namespace, '\\') . '\\' . $to;
}
// Always ensure that we escape our namespace so we're not pointing to
// \CodeIgniter\Routes\Controller::method.
$to = '\\' . ltrim($to, '\\');
}
$name = $options['as'] ?? $from;
helper('array');
// Don't overwrite any existing 'froms' so that auto-discovered routes
// do not overwrite any app/Config/Routes settings. The app
// routes should always be the "source of truth".
// this works only because discovered routes are added just prior
// to attempting to route the request.
// TODO: see how to overwrite routes differently
// restored change that broke Castopod routing with fediverse
// in CI4 v4.2.8 https://github.com/codeigniter4/CodeIgniter4/pull/6644
if (isset($this->routes[$verb][$name]) && ! $overwrite) {
return;
}
$this->routes[$verb][$name] = [
'route' => [
$from => $to,
],
];
$this->routesOptions[$verb][$from] = $options;
// Is this a redirect?
if (isset($options['redirect']) && is_numeric($options['redirect'])) {
$this->routes['*'][$name]['redirect'] = $options['redirect'];
}
}
}

View File

@ -1,6 +1,7 @@
import { import {
arrow, arrow,
computePosition, computePosition,
Coords,
flip, flip,
offset, offset,
Placement, Placement,
@ -46,7 +47,7 @@ const Tooltip = (): void => {
}); });
// Accessing the data // Accessing the data
const { x: arrowX, y: arrowY } = middlewareData.arrow as any; const { x: arrowX, y: arrowY } = middlewareData.arrow as Coords;
const staticSide = { const staticSide = {
top: "bottom", top: "bottom",

View File

@ -7,7 +7,7 @@ import {
queryAssignedElements, queryAssignedElements,
state, state,
} from "lit/decorators.js"; } from "lit/decorators.js";
import WaveSurfer from "wavesurfer.js"; import WaveSurfer, { WaveSurferOptions } from "wavesurfer.js";
enum ActionType { enum ActionType {
StretchLeft, StretchLeft,
@ -17,7 +17,9 @@ enum ActionType {
interface Action { interface Action {
type: ActionType; type: ActionType;
payload?: any; payload?: {
offset: number;
};
} }
interface EventElement { interface EventElement {
@ -300,7 +302,7 @@ export class AudioClipper extends LitElement {
responsive: true, responsive: true,
waveColor: "hsl(0 5% 85%)", waveColor: "hsl(0 5% 85%)",
cursorColor: "transparent", cursorColor: "transparent",
}); } as WaveSurferOptions);
this._wavesurfer.load(this._audio[0].src); this._wavesurfer.load(this._audio[0].src);
this.addEventListeners(); this.addEventListeners();

View File

@ -42,7 +42,7 @@ export class MarkdownPreview extends LitElement {
markdownToHtml(): string { markdownToHtml(): string {
const renderer = new marked.Renderer(); const renderer = new marked.Renderer();
renderer.link = function () { renderer.link = function () {
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params, @typescript-eslint/no-explicit-any
const link = marked.Renderer.prototype.link.apply(this, arguments as any); const link = marked.Renderer.prototype.link.apply(this, arguments as any);
return link.replace("<a", "<a target='_blank' rel='noopener noreferrer'"); return link.replace("<a", "<a target='_blank' rel='noopener noreferrer'");
}; };

View File

@ -7,13 +7,13 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"require": { "require": {
"php": "^8.1", "php": "^8.1",
"codeigniter4/framework": "v4.3.6", "codeigniter4/framework": "v4.3.7",
"james-heinrich/getid3": "^2.0.0-beta5", "james-heinrich/getid3": "^2.0.0-beta5",
"whichbrowser/parser": "^v2.1.7", "whichbrowser/parser": "^v2.1.7",
"geoip2/geoip2": "v2.13.0", "geoip2/geoip2": "v2.13.0",
"league/commonmark": "^2.4.0", "league/commonmark": "^2.4.0",
"vlucas/phpdotenv": "v5.5.0", "vlucas/phpdotenv": "v5.5.0",
"league/html-to-markdown": "^v5.1.0", "league/html-to-markdown": "5.1.1",
"opawg/user-agents-php": "^v1.0", "opawg/user-agents-php": "^v1.0",
"adaures/ipcat-php": "^v1.0.0", "adaures/ipcat-php": "^v1.0.0",
"adaures/podcast-persons-taxonomy": "^v1.0.1", "adaures/podcast-persons-taxonomy": "^v1.0.1",
@ -23,19 +23,19 @@
"chrisjean/php-ico": "^1.0.4", "chrisjean/php-ico": "^1.0.4",
"melbahja/seo": "^v2.1.1", "melbahja/seo": "^v2.1.1",
"codeigniter4/shield": "v1.0.0-beta.6", "codeigniter4/shield": "v1.0.0-beta.6",
"aws/aws-sdk-php": "^3.275.3", "aws/aws-sdk-php": "^3.279.2",
"mpratt/embera": "^2.0.34", "mpratt/embera": "^2.0.34",
"codeigniter4/tasks": "dev-develop", "codeigniter4/tasks": "dev-develop",
"yassinedoghri/podcast-feed": "dev-main" "yassinedoghri/podcast-feed": "dev-main"
}, },
"require-dev": { "require-dev": {
"mikey179/vfsstream": "^v1.6.11", "mikey179/vfsstream": "^v1.6.11",
"phpunit/phpunit": "^10.2.3", "phpunit/phpunit": "^10.3.2",
"captainhook/captainhook": "^5.16.4", "captainhook/captainhook": "^5.16.4",
"symplify/easy-coding-standard": "^11.5.0", "symplify/easy-coding-standard": "^12.0.6",
"phpstan/phpstan": "^1.10.25", "phpstan/phpstan": "^1.10.29",
"rector/rector": "^0.17.2", "rector/rector": "^0.18.0",
"symplify/coding-standard": "^11.4.1" "symplify/coding-standard": "^12.0.3"
}, },
"autoload": { "autoload": {
"exclude-from-classmap": [ "exclude-from-classmap": [

13697
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ use PhpCsFixer\Fixer\StringNotation\SingleQuoteFixer;
use PhpCsFixer\Fixer\Whitespace\IndentationTypeFixer; use PhpCsFixer\Fixer\Whitespace\IndentationTypeFixer;
use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer; use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer;
use Symplify\CodingStandard\Fixer\Naming\StandardizeHereNowDocKeywordFixer; use Symplify\CodingStandard\Fixer\Naming\StandardizeHereNowDocKeywordFixer;
use Symplify\CodingStandard\Fixer\Spacing\MethodChainingNewlineFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig; use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList; use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
@ -51,6 +52,12 @@ return static function (ECSConfig $ecsConfig): void {
__DIR__ . '/themes/*', __DIR__ . '/themes/*',
], ],
MethodChainingNewlineFixer::class => [
__DIR__ . '/app/Views/*',
__DIR__ . '/modules/**/Views/*',
__DIR__ . '/themes/*',
],
// crowdin enforces its own style for translation files // crowdin enforces its own style for translation files
// remove SingleQuoteFixer for Language files to prevent conflicts // remove SingleQuoteFixer for Language files to prevent conflicts
SingleQuoteFixer::class => [__DIR__ . '/app/Language/*', __DIR__ . '/modules/**/Language/*'], SingleQuoteFixer::class => [__DIR__ . '/app/Language/*', __DIR__ . '/modules/**/Language/*'],

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Modules\Fediverse\Config; namespace Modules\Fediverse\Config;
use Modules\Fediverse\Filters\AllowCorsFilter;
use Modules\Fediverse\Filters\FediverseFilter; use Modules\Fediverse\Filters\FediverseFilter;
class Registrar class Registrar
@ -13,8 +12,7 @@ class Registrar
{ {
return [ return [
'aliases' => [ 'aliases' => [
'fediverse' => FediverseFilter::class, 'fediverse' => FediverseFilter::class,
'allow-cors' => AllowCorsFilter::class,
], ],
]; ];
} }

View File

@ -243,6 +243,8 @@ class InstallController extends Controller
{ {
$migrate = Services::migrations(); $migrate = Services::migrations();
$migrate->setNamespace('CodeIgniter\Settings')
->latest();
$migrate->setNamespace(null) $migrate->setNamespace(null)
->latest(); ->latest();
} }

View File

@ -72,7 +72,7 @@ class AddMedia extends BaseMigration
]); ]);
$this->forge->addKey('id', true); $this->forge->addKey('id', true);
$this->forge->addUniqueKey('file_key'); $this->forge->addUniqueKey('file_path');
$this->forge->addForeignKey('uploaded_by', 'users', 'id'); $this->forge->addForeignKey('uploaded_by', 'users', 'id');
$this->forge->addForeignKey('updated_by', 'users', 'id'); $this->forge->addForeignKey('updated_by', 'users', 'id');
$this->forge->createTable('media'); $this->forge->createTable('media');

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Modules\Update\Commands; namespace Modules\Update\Commands;
use CodeIgniter\CLI\BaseCommand; use CodeIgniter\CLI\BaseCommand;
use Config\Services;
class DatabaseUpdate extends BaseCommand class DatabaseUpdate extends BaseCommand
{ {
@ -25,8 +26,11 @@ class DatabaseUpdate extends BaseCommand
public function run(array $params): void public function run(array $params): void
{ {
$this->call('migrate', [ $migrate = Services::migrations();
'all' => true,
]); $migrate->setNamespace('CodeIgniter\Settings')
->latest();
$migrate->setNamespace(null)
->latest();
} }
} }

View File

@ -27,70 +27,68 @@
"prepare": "is-ci || husky install" "prepare": "is-ci || husky install"
}, },
"dependencies": { "dependencies": {
"@amcharts/amcharts4": "^4.10.36", "@amcharts/amcharts4": "^4.10.38",
"@amcharts/amcharts4-geodata": "^4.1.27", "@amcharts/amcharts4-geodata": "^4.1.27",
"@codemirror/commands": "^6.2.4", "@codemirror/commands": "^6.2.4",
"@codemirror/lang-xml": "^6.0.2", "@codemirror/lang-xml": "^6.0.2",
"@codemirror/language": "^6.8.0", "@codemirror/language": "^6.9.0",
"@codemirror/state": "^6.2.1", "@codemirror/state": "^6.2.1",
"@codemirror/view": "^6.14.0", "@codemirror/view": "^6.16.0",
"@floating-ui/dom": "^1.4.3", "@floating-ui/dom": "^1.5.1",
"@github/clipboard-copy-element": "^1.2.1", "@github/clipboard-copy-element": "^1.2.1",
"@github/hotkey": "^2.0.1", "@github/hotkey": "^2.0.1",
"@github/markdown-toolbar-element": "^2.1.1", "@github/markdown-toolbar-element": "^2.2.0",
"@github/relative-time-element": "^4.3.0", "@github/relative-time-element": "^4.3.0",
"@tailwindcss/nesting": "0.0.0-insiders.565cd3e", "@tailwindcss/nesting": "0.0.0-insiders.565cd3e",
"@vime/core": "^5.4.0", "@vime/core": "^5.4.1",
"choices.js": "^10.2.0", "choices.js": "^10.2.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
"flatpickr": "^4.6.13", "flatpickr": "^4.6.13",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3", "leaflet.markercluster": "^1.5.3",
"lit": "^2.7.5", "lit": "^2.8.0",
"marked": "^5.1.0", "marked": "^7.0.4",
"wavesurfer.js": "^6.6.4", "wavesurfer.js": "^7.1.5",
"xml-formatter": "^3.4.1" "xml-formatter": "^3.5.0"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.6.6", "@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.6.6", "@commitlint/config-conventional": "^17.7.0",
"@csstools/css-tokenizer": "^2.1.1", "@csstools/css-tokenizer": "^2.2.0",
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3", "@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"@semantic-release/gitlab": "^12.0.3", "@semantic-release/gitlab": "^12.0.5",
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.4",
"@tailwindcss/typography": "^0.5.9", "@tailwindcss/typography": "^0.5.9",
"@types/leaflet": "^1.9.3", "@types/leaflet": "^1.9.3",
"@types/marked": "^5.0.0", "@typescript-eslint/eslint-plugin": "^6.4.0",
"@types/wavesurfer.js": "^6.0.6", "@typescript-eslint/parser": "^6.4.0",
"@typescript-eslint/eslint-plugin": "^5.60.1", "all-contributors-cli": "^6.26.1",
"@typescript-eslint/parser": "^5.60.1",
"all-contributors-cli": "^6.26.0",
"commitizen": "^4.3.0", "commitizen": "^4.3.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"cssnano": "^6.0.1", "cssnano": "^6.0.1",
"cz-conventional-changelog": "^3.3.0", "cz-conventional-changelog": "^3.3.0",
"eslint": "^8.44.0", "eslint": "^8.47.0",
"eslint-config-prettier": "^8.8.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.3", "husky": "^8.0.3",
"is-ci": "^3.0.1", "is-ci": "^3.0.1",
"lint-staged": "^13.2.3", "lint-staged": "^14.0.1",
"postcss": "^8.4.24", "postcss": "^8.4.28",
"postcss-import": "^15.1.0", "postcss-import": "^15.1.0",
"postcss-nesting": "^11.3.0", "postcss-nesting": "^12.0.1",
"postcss-preset-env": "^8.5.1", "postcss-preset-env": "^9.1.1",
"postcss-reporter": "^7.0.5", "postcss-reporter": "^7.0.5",
"prettier": "2.8.8", "prettier": "2.8.8",
"prettier-plugin-organize-imports": "^3.2.2", "prettier-plugin-organize-imports": "^3.2.3",
"semantic-release": "^21.0.6", "semantic-release": "^21.0.9",
"stylelint": "^15.9.0", "stylelint": "^15.10.3",
"stylelint-config-standard": "^33.0.0", "stylelint-config-standard": "^34.0.0",
"svgo": "^3.0.2", "svgo": "^3.0.2",
"tailwindcss": "^3.3.2", "tailwindcss": "^3.3.3",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"vite": "^4.3.9", "vite": "^4.4.9",
"vite-plugin-pwa": "^0.16.4", "vite-plugin-pwa": "^0.16.4",
"workbox-build": "^7.0.0", "workbox-build": "^7.0.0",
"workbox-core": "^7.0.0", "workbox-core": "^7.0.0",

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,7 @@ $userPodcasts = get_podcasts_user_can_interact_with(auth()->user()); ?>
<span class="absolute top-2 right-2 w-2.5 h-2.5 bg-red-500 rounded-full border border-navigation-bg"></span> <span class="absolute top-2 right-2 w-2.5 h-2.5 bg-red-500 rounded-full border border-navigation-bg"></span>
<?php endif ?> <?php endif ?>
</button> </button>
<?php <?php $notificationsTitle = lang('Notifications.title');
$notificationsTitle = lang('Notifications.title');
$items = [ $items = [
[ [

View File

@ -48,20 +48,13 @@ $podcastNavigation = [
<?php foreach ($podcastNavigation as $section => $data): ?> <?php foreach ($podcastNavigation as $section => $data): ?>
<div> <div>
<button class="inline-flex items-center w-full px-4 py-1 font-semibold focus:ring-accent" type="button"> <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') . <?= icon($data['icon'], 'opacity-60 text-2xl mr-4') . lang('EpisodeNavigation.' . $section) ?>
lang('EpisodeNavigation.' . $section) ?>
</button> </button>
<ul class="flex flex-col"> <ul class="flex flex-col">
<?php foreach ($data['items'] as $item): ?> <?php foreach ($data['items'] as $item): ?>
<?php $isActive = url_is(route_to($item, $podcast->id, $episode->id)); ?> <?php $isActive = url_is(route_to($item, $podcast->id, $episode->id)); ?>
<li class="inline-flex"> <li class="inline-flex">
<a class="w-full py-1 pl-14 pr-2 text-sm hover:opacity-100 focus:ring-inset focus:ring-accent <?= $isActive <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, $podcast->id, $episode->id) ?>"><?= ($isActive ? icon('chevron-right', 'mr-2') : '') . lang('EpisodeNavigation.' . $item) ?></a>
? 'font-semibold opacity-100 inline-flex items-center'
: 'opacity-75' ?>" href="<?= route_to(
$item,
$podcast->id,
$episode->id
) ?>"><?= ($isActive ? icon('chevron-right', 'mr-2') : '') . lang('EpisodeNavigation.' . $item) ?></a>
</li> </li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>

View File

@ -59,5 +59,5 @@
<?= service('vite') <?= service('vite')
->asset('js/charts.ts', 'js') ?> ->asset('js/charts.ts', 'js') ?>
<?= $this->endSection() ?> <?= $this->endSection() ?>

View File

@ -72,14 +72,12 @@ $counts = [
<?php foreach ($podcastNavigation as $section => $data): ?> <?php foreach ($podcastNavigation as $section => $data): ?>
<div> <div>
<button class="inline-flex items-center w-full px-4 py-1 font-semibold focus:ring-accent" type="button"> <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') . <?= icon($data['icon'], 'opacity-60 text-2xl mr-4') . lang('PodcastNavigation.' . $section) ?>
lang('PodcastNavigation.' . $section) ?>
</button> </button>
<ul class="flex flex-col"> <ul class="flex flex-col">
<?php foreach ($data['items'] as $item): ?> <?php foreach ($data['items'] as $item): ?>
<?php $isActive = url_is(route_to($item, $podcast->id)); ?> <?php $isActive = url_is(route_to($item, $podcast->id));
<?php $itemLabel = lang('PodcastNavigation.' . $item);
$itemLabel = lang('PodcastNavigation.' . $item);
if (array_key_exists($item, $counts)) { if (array_key_exists($item, $counts)) {
$itemLabel .= ' (' . $counts[$item] . ')'; $itemLabel .= ' (' . $counts[$item] . ')';
} }

View File

@ -27,5 +27,5 @@
</div> </div>
<?= service('vite') <?= service('vite')
->asset('js/charts.ts', 'js') ?> ->asset('js/charts.ts', 'js') ?>
<?= $this->endSection() ?> <?= $this->endSection() ?>

View File

@ -25,5 +25,5 @@
</div> </div>
<?= service('vite') <?= service('vite')
->asset('js/charts.ts', 'js') ?> ->asset('js/charts.ts', 'js') ?>
<?= $this->endSection() ?> <?= $this->endSection() ?>

View File

@ -27,5 +27,5 @@
</div> </div>
<?= service('vite') <?= service('vite')
->asset('js/charts.ts', 'js') ?> ->asset('js/charts.ts', 'js') ?>
<?= $this->endSection() ?> <?= $this->endSection() ?>

View File

@ -48,45 +48,46 @@
<?php endif; ?> <?php endif; ?>
<div class="inline-flex mt-1 bg-highlight"> <div class="inline-flex mt-1 bg-highlight">
<?= anchor($platform->home_url, icon('external-link', 'mx-auto'), [ <?= anchor($platform->home_url, icon('external-link', 'mx-auto'), [
'class' => 'flex-1 text-skin-muted hover:text-skin-base', 'class' => 'flex-1 text-skin-muted hover:text-skin-base',
'target' => '_blank', 'target' => '_blank',
'rel' => 'noopener noreferrer', 'rel' => 'noopener noreferrer',
'data-tooltip' => 'bottom', 'data-tooltip' => 'bottom',
'title' => lang('Platforms.home_url', [ 'title' => lang('Platforms.home_url', [
'platformName' => $platform->label, 'platformName' => $platform->label,
]), ]),
]) ?> ]) ?>
<?= $platform->submit_url <?= $platform->submit_url ? anchor(
? anchor($platform->submit_url, icon('add', 'mx-auto'), [ $platform->submit_url,
'class' => 'flex-1 text-skin-muted hover:text-skin-base', icon('add', 'mx-auto'),
'target' => '_blank', [
'rel' => 'noopener noreferrer', 'class' => 'flex-1 text-skin-muted hover:text-skin-base',
'data-tooltip' => 'bottom', 'target' => '_blank',
'title' => lang('Platforms.submit_url', [ 'rel' => 'noopener noreferrer',
'platformName' => $platform->label, 'data-tooltip' => 'bottom',
]), 'title' => lang('Platforms.submit_url', [
]) 'platformName' => $platform->label,
: '' ?> ]),
]
) : '' ?>
</div> </div>
</div> </div>
<div class="flex flex-col flex-1"> <div class="flex flex-col flex-1">
<?= $platform->link_url <?= $platform->link_url ? anchor(
? anchor( route_to(
route_to( 'podcast-platform-remove',
'podcast-platform-remove', $podcast->id,
$podcast->id, esc($platform->slug),
esc($platform->slug), ),
), icon('delete-bin', 'mx-auto'),
icon('delete-bin', 'mx-auto'), [
[ 'class' => 'absolute right-0 p-1 bg-red-100 rounded-full text-red-700 hover:text-red-900',
'class' => 'absolute right-0 p-1 bg-red-100 rounded-full text-red-700 hover:text-red-900', 'data-tooltip' => 'bottom',
'data-tooltip' => 'bottom', 'title' => lang('Platforms.remove', [
'title' => lang('Platforms.remove', [ 'platformName' => $platform->label,
'platformName' => $platform->label, ]),
]), ],
], )
) : '' ?>
: '' ?>
<fieldset> <fieldset>
<legend class="mb-2 font-semibold"><?= $platform->label ?></legend> <legend class="mb-2 font-semibold"><?= $platform->label ?></legend>
<Forms.Input <Forms.Input

View File

@ -17,21 +17,14 @@
[ [
'numberOfReblogs' => $post->reblogs_count, 'numberOfReblogs' => $post->reblogs_count,
], ],
) ?>"><?= icon('repeat', 'text-2xl mr-1 opacity-40') . ) ?>"><?= icon('repeat', 'text-2xl mr-1 opacity-40') . $post->reblogs_count ?></button>
$post->reblogs_count ?></button>
<button type="submit" name="action" value="favourite" class="inline-flex items-center hover:underline" title="<?= lang( <button type="submit" name="action" value="favourite" class="inline-flex items-center hover:underline" title="<?= lang(
'Post.favourites', 'Post.favourites',
[ [
'numberOfFavourites' => $post->favourites_count, 'numberOfFavourites' => $post->favourites_count,
], ],
) ?>"><?= icon('heart', 'text-2xl mr-1 opacity-40') . ) ?>"><?= icon('heart', 'text-2xl mr-1 opacity-40') . $post->favourites_count ?></button>
$post->favourites_count ?></button> <button id="<?= $post->id . '-more-dropdown' ?>" type="button" class="px-2 py-1 text-2xl text-skin-muted focus:ring-accent" data-dropdown="button" data-dropdown-target="<?= $post->id . '-more-dropdown-menu' ?>" aria-label="<?= lang('Common.more') ?>" aria-haspopup="true" aria-expanded="false"><?= icon('more') ?></button>
<button id="<?= $post->id .
'-more-dropdown' ?>" type="button" class="px-2 py-1 text-2xl text-skin-muted focus:ring-accent" data-dropdown="button" data-dropdown-target="<?= $post->id .
'-more-dropdown-menu' ?>" aria-label="<?= lang(
'Common.more',
) ?>" aria-haspopup="true" aria-expanded="false"><?= icon('more') ?>
</button>
</form> </form>
<nav id="<?= $post->id . <nav id="<?= $post->id .
'-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm rounded-lg shadow border-3 border-subtle bg-elevated" aria-labelledby="<?= $post->id . '-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm rounded-lg shadow border-3 border-subtle bg-elevated" aria-labelledby="<?= $post->id .

View File

@ -19,24 +19,16 @@ if (can_user_interact()): ?>
[ [
'numberOfReblogs' => $reply->reblogs_count, 'numberOfReblogs' => $reply->reblogs_count,
], ],
) ?>"><?= icon('repeat', 'text-lg mr-1 opacity-40') . ) ?>"><?= icon('repeat', 'text-lg mr-1 opacity-40') . $reply->reblogs_count ?></button>
$reply->reblogs_count ?></button>
<button type="submit" name="action" value="favourite" class="inline-flex items-center text-sm hover:underline" title="<?= lang( <button type="submit" name="action" value="favourite" class="inline-flex items-center text-sm hover:underline" title="<?= lang(
'Post.favourites', 'Post.favourites',
[ [
'numberOfFavourites' => $reply->favourites_count, 'numberOfFavourites' => $reply->favourites_count,
], ],
) ?>"><?= icon('heart', 'text-lg mr-1 opacity-40') . ) ?>"><?= icon('heart', 'text-lg mr-1 opacity-40') . $reply->favourites_count ?></button>
$reply->favourites_count ?></button> <button id="<?= $reply->id . '-more-dropdown' ?>" type="button" class="text-xl text-skin-muted focus:ring-accent" data-dropdown="button" data-dropdown-target="<?= $reply->id . '-more-dropdown-menu' ?>" aria-label="<?= lang('Common.more') ?>" aria-haspopup="true" aria-expanded="false"><?= icon('more') ?></button>
<button id="<?= $reply->id .
'-more-dropdown' ?>" type="button" class="text-xl text-skin-muted focus:ring-accent" data-dropdown="button" data-dropdown-target="<?= $reply->id .
'-more-dropdown-menu' ?>" aria-label="<?= lang(
'Common.more',
) ?>" aria-haspopup="true" aria-expanded="false"><?= icon('more') ?>
</button>
</form> </form>
<nav id="<?= $reply->id . <nav id="<?= $reply->id . '-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm rounded-lg shadow border-3 border-subtle bg-elevated" aria-labelledby="<?= $reply->id .
'-more-dropdown-menu' ?>" class="flex flex-col py-2 text-sm rounded-lg shadow border-3 border-subtle bg-elevated" aria-labelledby="<?= $reply->id .
'-more-dropdown' ?>" data-dropdown="menu" data-dropdown-placement="bottom"> '-more-dropdown' ?>" data-dropdown="menu" data-dropdown-placement="bottom">
<?= anchor( <?= anchor(
route_to('post', esc($podcast->handle), $reply->id), route_to('post', esc($podcast->handle), $reply->id),
@ -47,8 +39,7 @@ if (can_user_interact()): ?>
) ?> ) ?>
<form action="<?= route_to( <form action="<?= route_to(
'post-attempt-block-actor', 'post-attempt-block-actor',
esc(interact_as_actor() esc(interact_as_actor()->username),
->username),
$reply->id, $reply->id,
) ?>" method="POST"> ) ?>" method="POST">
<?= csrf_field() ?> <?= csrf_field() ?>

View File

@ -21,9 +21,9 @@
<Forms.Field <Forms.Field
name="db_hostname" name="db_hostname"
label="<?= lang('Install.form.db_hostname') ?>" label="<?= lang('Install.form.db_hostname') ?>"
value="<?= config('Database') value="<?= config('Database')->default['hostname'] ?>"
->default['hostname'] ?>" required="true"
required="true" /> />
<Forms.Field <Forms.Field
name="db_name" name="db_name"