feat: admin settings page UI/UX pass with WordPress-native patterns
- Header: h1 + logo in a wrapping flex row, hr.wp-header-end before the tabs, aria-current on the active tab; own CSS/JS enqueued only on this screen. - Verbindung: ordered "So verbindest du Claude" steps, copy button (core clipboard.js + wp.a11y.speak), Site-Health-style status list, German details. - Zugriff: roles as form-table fieldset, connections with site date format, empty-state row, confirm on revoke; ConnectionUsage records last use via WP_Application_Passwords::record_application_password_usage (once a day). - Tools: plain-language legend, counter as inline notice, groups as core postboxes (postbox.js toggles, per-user closed state, summary when closed), fixed column widths with new "Art" column, submit above and below. - Protokoll: site-timezone times with UTC tooltip, result icons, filters with labels in the list table nav, retention link to Limits. - Limits: short labels with units and descriptions; snapshot count hidden but preserved. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+48
-12
@@ -11,15 +11,24 @@ final class SettingsPage
|
||||
{
|
||||
public const SLUG = 'lit-mcp';
|
||||
|
||||
/** Hook suffix WordPress gives this page (add_options_page → "settings_page_<slug>"). */
|
||||
public const SCREEN_HOOK = 'settings_page_' . self::SLUG;
|
||||
|
||||
/** @var array<string, AdminTab> */
|
||||
private array $tabs = [];
|
||||
|
||||
/**
|
||||
* @param list<AdminTab> $tabs The first tab is the default.
|
||||
* @param string $logoUrl Loosen-IT logo shown top right of the page ('' = none).
|
||||
* @param string $logoUrl Loosen-IT logo shown top right of the page ('' = none).
|
||||
* @param string $assetsUrl URL of the plugin's assets/ directory ('' = no own CSS/JS).
|
||||
* @param string $version Asset version for cache busting.
|
||||
*/
|
||||
public function __construct(array $tabs, private string $logoUrl = '')
|
||||
{
|
||||
public function __construct(
|
||||
array $tabs,
|
||||
private string $logoUrl = '',
|
||||
private string $assetsUrl = '',
|
||||
private string $version = ''
|
||||
) {
|
||||
foreach ($tabs as $tab) {
|
||||
$this->tabs[$tab->slug()] = $tab;
|
||||
}
|
||||
@@ -29,6 +38,7 @@ final class SettingsPage
|
||||
{
|
||||
add_action('admin_menu', [$this, 'addMenu']);
|
||||
add_action('admin_init', [$this, 'registerSettings']);
|
||||
add_action('admin_enqueue_scripts', [$this, 'enqueueAssets']);
|
||||
foreach ($this->tabs as $tab) {
|
||||
$tab->registerActions();
|
||||
}
|
||||
@@ -52,6 +62,29 @@ final class SettingsPage
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Own CSS and a small script, only on this page. The script builds on WordPress' own
|
||||
* clipboard.js and wp.a11y.speak (as the media modal's "Copy URL") and postbox.js.
|
||||
*/
|
||||
public function enqueueAssets(string $hook): void
|
||||
{
|
||||
if ($hook !== self::SCREEN_HOOK || $this->assetsUrl === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$base = rtrim($this->assetsUrl, '/');
|
||||
wp_enqueue_style('lit-mcp-admin', $base . '/css/admin.css', [], $this->version);
|
||||
$deps = ['clipboard', 'wp-a11y'];
|
||||
if ($this->currentTab() === 'tools') {
|
||||
// Collapsible tool groups use WordPress' own postbox toggles (remembered per user).
|
||||
$deps[] = 'postbox';
|
||||
}
|
||||
wp_enqueue_script('lit-mcp-admin', $base . '/js/admin.js', $deps, $this->version, true);
|
||||
wp_localize_script('lit-mcp-admin', 'litMcpAdmin', [
|
||||
'copied' => __('Die URL wurde in die Zwischenablage kopiert.', 'wp-lit-mcp'),
|
||||
]);
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
public function tabSlugs(): array
|
||||
{
|
||||
@@ -81,16 +114,19 @@ final class SettingsPage
|
||||
}
|
||||
|
||||
$current = $this->currentTab();
|
||||
echo '<div class="wrap">';
|
||||
echo '<div class="wrap lit-mcp">';
|
||||
echo '<div class="lit-mcp-header"><h1>' . esc_html__('LIT MCP', 'wp-lit-mcp') . '</h1>';
|
||||
$this->renderLogo();
|
||||
echo '<h1>' . esc_html__('LIT MCP', 'wp-lit-mcp') . '</h1>';
|
||||
// Admin notices of other plugins are moved right after this marker – above the tabs.
|
||||
echo '</div><hr class="wp-header-end">';
|
||||
$this->renderNotice();
|
||||
echo '<nav class="nav-tab-wrapper">';
|
||||
printf('<nav class="nav-tab-wrapper wp-clearfix" aria-label="%s">', esc_attr__('Bereiche', 'wp-lit-mcp'));
|
||||
foreach ($this->tabs as $slug => $tab) {
|
||||
printf(
|
||||
'<a href="%s" class="nav-tab%s">%s</a>',
|
||||
'<a href="%s" class="nav-tab%s"%s>%s</a>',
|
||||
esc_url(self::url($slug)),
|
||||
$slug === $current ? ' nav-tab-active' : '',
|
||||
$slug === $current ? ' aria-current="page"' : '',
|
||||
esc_html($tab->label())
|
||||
);
|
||||
}
|
||||
@@ -106,11 +142,11 @@ final class SettingsPage
|
||||
}
|
||||
|
||||
printf(
|
||||
'<div class="lit-mcp-header"><a href="https://loosen-it.de" target="_blank" rel="noopener">'
|
||||
. '<img src="%s" alt="Loosen-IT Logo" class="lit-mcp-logo"></a></div>'
|
||||
. '<style>.lit-mcp-header{position:relative}.lit-mcp-logo{position:absolute;padding:10px;right:0;'
|
||||
. 'top:0;height:30px;width:auto}@media (max-width:782px){.lit-mcp-logo{height:24px}}</style>',
|
||||
esc_url($this->logoUrl)
|
||||
'<a class="lit-mcp-logo-link" href="https://loosen-it.de" target="_blank" rel="noopener">'
|
||||
. '<img src="%s" alt="Loosen-IT Logo" class="lit-mcp-logo">'
|
||||
. '<span class="screen-reader-text"> %s</span></a>',
|
||||
esc_url($this->logoUrl),
|
||||
esc_html__('(öffnet in einem neuen Tab)', 'wp-lit-mcp')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user