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);
use Config\Services;
use Config\View;
use ViewThemes\Theme;
@ -49,42 +48,3 @@ if (! function_exists('view')) {
->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;
use App\Filters\AllowCorsFilter;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Filters\CSRF;
use CodeIgniter\Filters\DebugToolbar;
@ -25,6 +26,7 @@ class Filters extends BaseConfig
'honeypot' => Honeypot::class,
'invalidchars' => InvalidChars::class,
'secureheaders' => SecureHeaders::class,
'allow-cors' => AllowCorsFilter::class,
];
/**

View File

@ -6,6 +6,7 @@ namespace Config;
use App\Libraries\Breadcrumb;
use App\Libraries\Negotiate;
use App\Libraries\RouteCollection;
use App\Libraries\Router;
use CodeIgniter\Config\BaseService;
use CodeIgniter\HTTP\Request;
@ -43,6 +44,21 @@ class Services extends BaseService
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
* 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 {
arrow,
computePosition,
Coords,
flip,
offset,
Placement,
@ -46,7 +47,7 @@ const Tooltip = (): void => {
});
// Accessing the data
const { x: arrowX, y: arrowY } = middlewareData.arrow as any;
const { x: arrowX, y: arrowY } = middlewareData.arrow as Coords;
const staticSide = {
top: "bottom",

View File

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

View File

@ -42,7 +42,7 @@ export class MarkdownPreview extends LitElement {
markdownToHtml(): string {
const renderer = new marked.Renderer();
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);
return link.replace("<a", "<a target='_blank' rel='noopener noreferrer'");
};

View File

@ -7,13 +7,13 @@
"license": "AGPL-3.0-or-later",
"require": {
"php": "^8.1",
"codeigniter4/framework": "v4.3.6",
"codeigniter4/framework": "v4.3.7",
"james-heinrich/getid3": "^2.0.0-beta5",
"whichbrowser/parser": "^v2.1.7",
"geoip2/geoip2": "v2.13.0",
"league/commonmark": "^2.4.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",
"adaures/ipcat-php": "^v1.0.0",
"adaures/podcast-persons-taxonomy": "^v1.0.1",
@ -23,19 +23,19 @@
"chrisjean/php-ico": "^1.0.4",
"melbahja/seo": "^v2.1.1",
"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",
"codeigniter4/tasks": "dev-develop",
"yassinedoghri/podcast-feed": "dev-main"
},
"require-dev": {
"mikey179/vfsstream": "^v1.6.11",
"phpunit/phpunit": "^10.2.3",
"phpunit/phpunit": "^10.3.2",
"captainhook/captainhook": "^5.16.4",
"symplify/easy-coding-standard": "^11.5.0",
"phpstan/phpstan": "^1.10.25",
"rector/rector": "^0.17.2",
"symplify/coding-standard": "^11.4.1"
"symplify/easy-coding-standard": "^12.0.6",
"phpstan/phpstan": "^1.10.29",
"rector/rector": "^0.18.0",
"symplify/coding-standard": "^12.0.3"
},
"autoload": {
"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 Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer;
use Symplify\CodingStandard\Fixer\Naming\StandardizeHereNowDocKeywordFixer;
use Symplify\CodingStandard\Fixer\Spacing\MethodChainingNewlineFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
@ -51,6 +52,12 @@ return static function (ECSConfig $ecsConfig): void {
__DIR__ . '/themes/*',
],
MethodChainingNewlineFixer::class => [
__DIR__ . '/app/Views/*',
__DIR__ . '/modules/**/Views/*',
__DIR__ . '/themes/*',
],
// crowdin enforces its own style for translation files
// remove SingleQuoteFixer for Language files to prevent conflicts
SingleQuoteFixer::class => [__DIR__ . '/app/Language/*', __DIR__ . '/modules/**/Language/*'],

View File

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

View File

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

View File

@ -72,7 +72,7 @@ class AddMedia extends BaseMigration
]);
$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('updated_by', 'users', 'id');
$this->forge->createTable('media');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,21 +17,14 @@
[
'numberOfReblogs' => $post->reblogs_count,
],
) ?>"><?= icon('repeat', 'text-2xl mr-1 opacity-40') .
$post->reblogs_count ?></button>
) ?>"><?= icon('repeat', 'text-2xl mr-1 opacity-40') . $post->reblogs_count ?></button>
<button type="submit" name="action" value="favourite" class="inline-flex items-center hover:underline" title="<?= lang(
'Post.favourites',
[
'numberOfFavourites' => $post->favourites_count,
],
) ?>"><?= icon('heart', 'text-2xl mr-1 opacity-40') .
$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>
) ?>"><?= icon('heart', 'text-2xl mr-1 opacity-40') . $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>
</form>
<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 .

View File

@ -19,24 +19,16 @@ if (can_user_interact()): ?>
[
'numberOfReblogs' => $reply->reblogs_count,
],
) ?>"><?= icon('repeat', 'text-lg mr-1 opacity-40') .
$reply->reblogs_count ?></button>
) ?>"><?= icon('repeat', 'text-lg mr-1 opacity-40') . $reply->reblogs_count ?></button>
<button type="submit" name="action" value="favourite" class="inline-flex items-center text-sm hover:underline" title="<?= lang(
'Post.favourites',
[
'numberOfFavourites' => $reply->favourites_count,
],
) ?>"><?= icon('heart', 'text-lg mr-1 opacity-40') .
$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>
) ?>"><?= icon('heart', 'text-lg mr-1 opacity-40') . $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>
</form>
<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 .
<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' ?>" data-dropdown="menu" data-dropdown-placement="bottom">
<?= anchor(
route_to('post', esc($podcast->handle), $reply->id),
@ -47,8 +39,7 @@ if (can_user_interact()): ?>
) ?>
<form action="<?= route_to(
'post-attempt-block-actor',
esc(interact_as_actor()
->username),
esc(interact_as_actor()->username),
$reply->id,
) ?>" method="POST">
<?= csrf_field() ?>

View File

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