Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19831cd2f3 | ||
|
|
faf9f35992 | ||
|
|
f5c48bced9 | ||
|
|
f0bc04a110 | ||
|
|
2fec4cf34b | ||
|
|
2da3883d20 | ||
|
|
b3ff365483 | ||
|
|
53ca6f62b9 | ||
|
|
dc2a4435c5 | ||
|
|
da856dc853 | ||
|
|
1c8c351654 | ||
|
|
ce8fcc8fdd |
+1
-2
@@ -1053,8 +1053,7 @@ and closed the one remaining documented security gap.
|
|||||||
- First phase of the "full admin takeover" initiative: Posts, Pages, Media
|
- First phase of the "full admin takeover" initiative: Posts, Pages, Media
|
||||||
Library, Users, and Comments no longer redirect to a separate
|
Library, Users, and Comments no longer redirect to a separate
|
||||||
`admin.php?page=...` URL — they now hijack their native screens in place
|
`admin.php?page=...` URL — they now hijack their native screens in place
|
||||||
(`ScreenHijack.php`, registered via `HijackedNativePages.php`), the same
|
(`ScreenHijack.php`, registered via `HijackedNativePages.php`). WordPress's
|
||||||
approach the original uixpress reference plugin used. WordPress's
|
|
||||||
`load-{page}.php` hook fires before the native screen prints anything, so
|
`load-{page}.php` hook fires before the native screen prints anything, so
|
||||||
Aurora buffers and discards the native output and mounts its own Vue page
|
Aurora buffers and discards the native output and mounts its own Vue page
|
||||||
in its place — the URL never changes, so there's no separate slug that can
|
in its place — the URL never changes, so there's no separate slug that can
|
||||||
|
|||||||
+7
-13
@@ -85,21 +85,15 @@ unless explicitly marked otherwise).)_
|
|||||||
|
|
||||||
## What this project is
|
## What this project is
|
||||||
|
|
||||||
A ground-up rebuild of the "uiXpress" WordPress admin-theme plugin, relaunched
|
**Aurora Admin** — a modern, fast WordPress admin interface. Real replacement
|
||||||
as **Aurora Admin**. The original plugin's look/feel and feature set are the
|
screens for the core admin (Posts, Pages, Media, Users, Comments, and more),
|
||||||
target, but **no original code is reused** — all Vue components, PHP classes,
|
a full theme system with dark mode, and admin power-tools, all freshly written
|
||||||
and build tooling are freshly written. This lives in `aurora-admin-v2/` (the
|
from scratch (Vue components, PHP classes, and build tooling).
|
||||||
earlier in-place rebrand attempt, `aurora-admin-working/`, is superseded and
|
|
||||||
no longer the active codebase).
|
|
||||||
|
|
||||||
## Repo
|
## Repo
|
||||||
|
|
||||||
Now on GitLab (self-hosted): `ssh://[email protected]:2289/NixReaper/aurora-wordpress-admin.git`
|
Now on GitLab (self-hosted): `ssh://[email protected]:2289/NixReaper/aurora-wordpress-admin.git`
|
||||||
(HTTPS also available). Repo root = the contents of `aurora-admin-v2/`
|
(HTTPS also available). Repo root holds `admin/`, `app/`, and `aurora-admin.php`.
|
||||||
(`admin/`, `app/`, `aurora-admin.php`), not the whole `uixpress/` folder — that
|
|
||||||
folder has a bunch of dead-end attempts (`aurora-admin-working`,
|
|
||||||
`aurora-admin-distribution`, `aurora-admin-rewrite`, `aurora-admin-GLM`,
|
|
||||||
`uixpress`) that are debugging history, not part of the project.
|
|
||||||
|
|
||||||
`.gitignore` excludes `app/node_modules/` and `app/dist/` (build output —
|
`.gitignore` excludes `app/node_modules/` and `app/dist/` (build output —
|
||||||
regenerate, don't version). To clone on a new machine: add an SSH key to the
|
regenerate, don't version). To clone on a new machine: add an SSH key to the
|
||||||
@@ -293,8 +287,8 @@ URL with no rewrite needed.
|
|||||||
|
|
||||||
**Plugins is the one exception, deliberately left on the old redirect
|
**Plugins is the one exception, deliberately left on the old redirect
|
||||||
mechanism** — `plugins.php` prints output in a way that can't be cleanly
|
mechanism** — `plugins.php` prints output in a way that can't be cleanly
|
||||||
buffered (confirmed by the old uixpress reference plugin's own abandoned
|
buffered (confirmed via a prior abandoned attempt at hijacking it the same
|
||||||
attempt at hijacking it the same way). It still has a real
|
way). It still has a real
|
||||||
`aurora-admin-plugins` submenu under `plugins.php` and its own
|
`aurora-admin-plugins` submenu under `plugins.php` and its own
|
||||||
`redirect_native_pages()` branch in `SubApps.php`.
|
`redirect_native_pages()` branch in `SubApps.php`.
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use AuroraAdmin\Options\Settings;
|
|||||||
use AuroraAdmin\Shell\Shell;
|
use AuroraAdmin\Shell\Shell;
|
||||||
use AuroraAdmin\Pages\DashboardTakeover;
|
use AuroraAdmin\Pages\DashboardTakeover;
|
||||||
use AuroraAdmin\Pages\SettingsPage;
|
use AuroraAdmin\Pages\SettingsPage;
|
||||||
|
use AuroraAdmin\Pages\SetupWizard;
|
||||||
use AuroraAdmin\Rest\DashboardData;
|
use AuroraAdmin\Rest\DashboardData;
|
||||||
use AuroraAdmin\Analytics\Analytics;
|
use AuroraAdmin\Analytics\Analytics;
|
||||||
use AuroraAdmin\Rest\AnalyticsData;
|
use AuroraAdmin\Rest\AnalyticsData;
|
||||||
@@ -45,6 +46,8 @@ use AuroraAdmin\Login\LoginStyle;
|
|||||||
use AuroraAdmin\Media\SvgUploads;
|
use AuroraAdmin\Media\SvgUploads;
|
||||||
use AuroraAdmin\Media\MediaFolders;
|
use AuroraAdmin\Media\MediaFolders;
|
||||||
use AuroraAdmin\ImageFormats\ImageFormats;
|
use AuroraAdmin\ImageFormats\ImageFormats;
|
||||||
|
use AuroraAdmin\Security\Security;
|
||||||
|
use AuroraAdmin\Code\CodeInjection;
|
||||||
use AuroraAdmin\Rest\MediaFolderData;
|
use AuroraAdmin\Rest\MediaFolderData;
|
||||||
use AuroraAdmin\Rest\BugReportData;
|
use AuroraAdmin\Rest\BugReportData;
|
||||||
use AuroraAdmin\Rest\CompanionPluginData;
|
use AuroraAdmin\Rest\CompanionPluginData;
|
||||||
@@ -63,6 +66,7 @@ class AuroraAdmin
|
|||||||
new Shell();
|
new Shell();
|
||||||
new DashboardTakeover();
|
new DashboardTakeover();
|
||||||
new SettingsPage();
|
new SettingsPage();
|
||||||
|
new SetupWizard();
|
||||||
new DashboardData();
|
new DashboardData();
|
||||||
new Analytics();
|
new Analytics();
|
||||||
new AnalyticsData();
|
new AnalyticsData();
|
||||||
@@ -95,6 +99,8 @@ class AuroraAdmin
|
|||||||
new SvgUploads();
|
new SvgUploads();
|
||||||
new MediaFolders();
|
new MediaFolders();
|
||||||
new ImageFormats();
|
new ImageFormats();
|
||||||
|
new Security();
|
||||||
|
new CodeInjection();
|
||||||
new MediaFolderData();
|
new MediaFolderData();
|
||||||
new BugReportData();
|
new BugReportData();
|
||||||
new CompanionPluginData();
|
new CompanionPluginData();
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
namespace AuroraAdmin\Code;
|
||||||
|
|
||||||
|
use AuroraAdmin\Options\Settings;
|
||||||
|
|
||||||
|
defined("ABSPATH") || exit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom code injection (Settings > Code).
|
||||||
|
*
|
||||||
|
* Four admin-authored fields, only settable by manage_options users on the
|
||||||
|
* settings page:
|
||||||
|
* - Admin CSS → wrapped in a <style> in the admin <head>
|
||||||
|
* - Admin JS → wrapped in a <script> in the admin footer
|
||||||
|
* - Header scripts → printed raw in the front-end <head>
|
||||||
|
* - Footer scripts → printed raw before the front-end </body>
|
||||||
|
*
|
||||||
|
* Header/footer scripts are printed verbatim (they're meant to hold full
|
||||||
|
* <script>/<meta> tags — analytics, verification, etc.), the same trusted-
|
||||||
|
* admin model as any "insert headers and footers" tool. Admin CSS/JS is the
|
||||||
|
* user's own code too, but is wrapped in the right tag for them and guarded
|
||||||
|
* against accidentally breaking out of that tag.
|
||||||
|
*/
|
||||||
|
class CodeInjection
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
add_action("admin_head", [self::class, "admin_css"], 999);
|
||||||
|
add_action("admin_print_footer_scripts", [self::class, "admin_js"], 999);
|
||||||
|
add_action("wp_head", [self::class, "header_scripts"], 999);
|
||||||
|
add_action("wp_footer", [self::class, "footer_scripts"], 999);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function admin_css()
|
||||||
|
{
|
||||||
|
$css = trim((string) Settings::get("custom_admin_css", ""));
|
||||||
|
if ($css === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Keep the CSS from breaking out of its own <style> element.
|
||||||
|
$css = str_ireplace("</style>", "", $css);
|
||||||
|
echo "\n<style id=\"aurora-custom-admin-css\">\n" . $css . "\n</style>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored stylesheet, output raw inside a <style> tag by design; </style> stripped above to prevent breakout.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function admin_js()
|
||||||
|
{
|
||||||
|
$js = trim((string) Settings::get("custom_admin_js", ""));
|
||||||
|
if ($js === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$js = str_ireplace("</script>", "<\\/script>", $js);
|
||||||
|
echo "\n<script id=\"aurora-custom-admin-js\">\n" . $js . "\n</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored script, output raw inside a <script> tag by design.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function header_scripts()
|
||||||
|
{
|
||||||
|
$code = trim((string) Settings::get("header_scripts", ""));
|
||||||
|
if ($code === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
echo "\n" . $code . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored header markup (scripts/meta), printed verbatim by design.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function footer_scripts()
|
||||||
|
{
|
||||||
|
$code = trim((string) Settings::get("footer_scripts", ""));
|
||||||
|
if ($code === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
echo "\n" . $code . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored footer markup (scripts), printed verbatim by design.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,10 +42,25 @@ class LoginStyle
|
|||||||
}
|
}
|
||||||
|
|
||||||
$logo = trim((string) Settings::get("login_logo", ""));
|
$logo = trim((string) Settings::get("login_logo", ""));
|
||||||
|
$bg_image = trim((string) Settings::get("login_bg_image", ""));
|
||||||
|
// Colors fall back to the original fixed dark theme when unset; invalid
|
||||||
|
// values are dropped by sanitize_hex_color (returns null) then fall back.
|
||||||
|
$bg_color = sanitize_hex_color((string) Settings::get("login_bg_color", "")) ?: "";
|
||||||
|
$form_bg = sanitize_hex_color((string) Settings::get("login_form_bg", "")) ?: "#1c2333";
|
||||||
|
$accent = sanitize_hex_color((string) Settings::get("login_button_color", "")) ?: "#4f7cff";
|
||||||
|
$custom_css = str_ireplace("</style>", "", (string) Settings::get("login_custom_css", ""));
|
||||||
|
|
||||||
|
if ($bg_image) {
|
||||||
|
$background = "url(" . esc_url($bg_image) . ") center / cover no-repeat";
|
||||||
|
} elseif ($bg_color) {
|
||||||
|
$background = $bg_color;
|
||||||
|
} else {
|
||||||
|
$background = "linear-gradient(135deg, #1b2333 0%, #0f1420 100%)";
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<style>
|
<style>
|
||||||
body.login {
|
body.login {
|
||||||
background: linear-gradient(135deg, #1b2333 0%, #0f1420 100%);
|
background: <?php echo $background; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- composed from a sanitize_hex_color() color or esc_url()'d image above. ?>;
|
||||||
}
|
}
|
||||||
body.login #login h1 a {
|
body.login #login h1 a {
|
||||||
<?php if ($logo): ?>
|
<?php if ($logo): ?>
|
||||||
@@ -64,7 +79,7 @@ class LoginStyle
|
|||||||
body.login form#loginform,
|
body.login form#loginform,
|
||||||
body.login form#registerform,
|
body.login form#registerform,
|
||||||
body.login form#lostpasswordform {
|
body.login form#lostpasswordform {
|
||||||
background: #1c2333;
|
background: <?php echo esc_attr($form_bg); ?>;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
|
||||||
@@ -84,8 +99,8 @@ class LoginStyle
|
|||||||
body.login input[type="text"]:focus,
|
body.login input[type="text"]:focus,
|
||||||
body.login input[type="password"]:focus,
|
body.login input[type="password"]:focus,
|
||||||
body.login input[type="email"]:focus {
|
body.login input[type="email"]:focus {
|
||||||
border-color: #4f7cff;
|
border-color: <?php echo esc_attr($accent); ?>;
|
||||||
box-shadow: 0 0 0 1px #4f7cff;
|
box-shadow: 0 0 0 1px <?php echo esc_attr($accent); ?>;
|
||||||
}
|
}
|
||||||
body.login .forgetmenot label {
|
body.login .forgetmenot label {
|
||||||
color: #9fb0d0;
|
color: #9fb0d0;
|
||||||
@@ -99,23 +114,23 @@ class LoginStyle
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
body.login .wp-core-ui .button-primary {
|
body.login .wp-core-ui .button-primary {
|
||||||
background: #4f7cff;
|
background: <?php echo esc_attr($accent); ?>;
|
||||||
border-color: #4f7cff;
|
border-color: <?php echo esc_attr($accent); ?>;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
body.login .wp-core-ui .button-primary:hover,
|
body.login .wp-core-ui .button-primary:hover,
|
||||||
body.login .wp-core-ui .button-primary:focus {
|
body.login .wp-core-ui .button-primary:focus {
|
||||||
background: #3b63e0;
|
filter: brightness(0.92);
|
||||||
border-color: #3b63e0;
|
|
||||||
}
|
}
|
||||||
body.login #login_error,
|
body.login #login_error,
|
||||||
body.login .message,
|
body.login .message,
|
||||||
body.login .success {
|
body.login .success {
|
||||||
background: #232b40;
|
background: #232b40;
|
||||||
border-left-color: #4f7cff;
|
border-left-color: <?php echo esc_attr($accent); ?>;
|
||||||
color: #e2e8f4;
|
color: #e2e8f4;
|
||||||
}
|
}
|
||||||
|
<?php echo $custom_css; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored login CSS, output raw by design; </style> stripped above. ?>
|
||||||
</style>
|
</style>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
<?php
|
||||||
|
namespace AuroraAdmin\Pages;
|
||||||
|
|
||||||
|
use AuroraAdmin\Utility\Assets;
|
||||||
|
use AuroraAdmin\Options\Settings;
|
||||||
|
|
||||||
|
defined("ABSPATH") || exit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First-run onboarding wizard.
|
||||||
|
*
|
||||||
|
* A full-screen, self-contained page (no Aurora sidebar/toolbar shell, no
|
||||||
|
* native WP chrome) walking a new user through appearance, branding, and
|
||||||
|
* which replacement screens to enable. Registered as a hidden submenu of the
|
||||||
|
* "aurora-admin" menu — MenuSerializer skips that slug, so it never shows in
|
||||||
|
* the Aurora sidebar, and the native menu it does technically live under is
|
||||||
|
* hidden by the shell on every other page anyway.
|
||||||
|
*
|
||||||
|
* First run: on activation an option flags a one-time redirect here; the
|
||||||
|
* wizard clears it and sets a "complete" option when finished or skipped, so
|
||||||
|
* it never auto-opens again (but stays reachable at its URL).
|
||||||
|
*/
|
||||||
|
class SetupWizard
|
||||||
|
{
|
||||||
|
const PAGE = "aurora-admin-setup";
|
||||||
|
const OPT_COMPLETE = "aurora_admin_setup_complete";
|
||||||
|
const OPT_REDIRECT = "aurora_admin_setup_redirect";
|
||||||
|
|
||||||
|
private static $hook_suffix = null;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
register_activation_hook(AURORA_ADMIN_PATH . "aurora-admin.php", [self::class, "on_activate"]);
|
||||||
|
add_action("admin_menu", [self::class, "register_menu"]);
|
||||||
|
add_action("admin_enqueue_scripts", [self::class, "maybe_enqueue"]);
|
||||||
|
add_action("admin_init", [self::class, "maybe_redirect"]);
|
||||||
|
add_action("rest_api_init", [self::class, "register_rest"]);
|
||||||
|
// Turn the immersive shell off on this page so the wizard owns the whole
|
||||||
|
// viewport; native chrome is hidden separately (printed below).
|
||||||
|
add_filter("aurora_admin_shell_enabled", [self::class, "disable_shell_here"]);
|
||||||
|
add_action("admin_head", [self::class, "hide_native_chrome"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Flag a one-time redirect to the wizard, unless setup was already done. */
|
||||||
|
public static function on_activate()
|
||||||
|
{
|
||||||
|
if (!get_option(self::OPT_COMPLETE)) {
|
||||||
|
update_option(self::OPT_REDIRECT, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function is_wizard_page()
|
||||||
|
{
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only page match; no state change.
|
||||||
|
return isset($_GET["page"]) && sanitize_text_field(wp_unslash($_GET["page"])) === self::PAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function disable_shell_here($enabled)
|
||||||
|
{
|
||||||
|
return self::is_wizard_page() ? false : $enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function register_menu()
|
||||||
|
{
|
||||||
|
self::$hook_suffix = add_submenu_page(
|
||||||
|
"aurora-admin",
|
||||||
|
__("Setup", "aurora-admin"),
|
||||||
|
__("Setup", "aurora-admin"),
|
||||||
|
"manage_options",
|
||||||
|
self::PAGE,
|
||||||
|
[self::class, "render"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function maybe_redirect()
|
||||||
|
{
|
||||||
|
if (!get_option(self::OPT_REDIRECT)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (wp_doing_ajax() || !current_user_can("manage_options") || self::is_wizard_page()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete_option(self::OPT_REDIRECT);
|
||||||
|
wp_safe_redirect(admin_url("admin.php?page=" . self::PAGE));
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function maybe_enqueue($hook_suffix)
|
||||||
|
{
|
||||||
|
if ($hook_suffix !== self::$hook_suffix) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Image fields (logo, dark logo, favicon) use the real media library.
|
||||||
|
wp_enqueue_media();
|
||||||
|
Assets::enqueue("aurora-admin-setup", "entries/setup-wizard.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Hide native WP chrome on the wizard page (the shell, which normally does
|
||||||
|
* this, is turned off here). The Vue app also renders as a full-screen
|
||||||
|
* overlay, but this keeps the admin bar/menu from flashing first. */
|
||||||
|
public static function hide_native_chrome()
|
||||||
|
{
|
||||||
|
if (!self::is_wizard_page()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<style id="aurora-setup-hide-chrome">
|
||||||
|
#adminmenumain, #wpadminbar, #wpfooter { display: none !important; }
|
||||||
|
html.wp-toolbar { padding-top: 0 !important; }
|
||||||
|
#wpcontent { margin-left: 0 !important; }
|
||||||
|
#wpbody-content { padding: 0 !important; float: none; width: auto; }
|
||||||
|
</style>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function register_rest()
|
||||||
|
{
|
||||||
|
register_rest_route("aurora-admin/v1", "/setup/complete", [
|
||||||
|
"methods" => "POST",
|
||||||
|
"callback" => [self::class, "rest_complete"],
|
||||||
|
"permission_callback" => function () {
|
||||||
|
return current_user_can("manage_options");
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function rest_complete()
|
||||||
|
{
|
||||||
|
update_option(self::OPT_COMPLETE, 1);
|
||||||
|
delete_option(self::OPT_REDIRECT);
|
||||||
|
return ["success" => true];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function render()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
"restUrl" => esc_url_raw(get_rest_url()),
|
||||||
|
"restNonce" => wp_create_nonce("wp_rest"),
|
||||||
|
"userName" => wp_get_current_user()->display_name,
|
||||||
|
"settings" => Settings::get(),
|
||||||
|
"dashboardUrl" => esc_url_raw(admin_url("index.php")),
|
||||||
|
"settingsUrl" => esc_url_raw(admin_url("admin.php?page=aurora-admin")),
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
<div
|
||||||
|
id="aurora-admin-setup-root"
|
||||||
|
data-aurora-admin="<?php echo esc_attr(wp_json_encode($data)); ?>"
|
||||||
|
></div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
<?php
|
||||||
|
namespace AuroraAdmin\Security;
|
||||||
|
|
||||||
|
use AuroraAdmin\Options\Settings;
|
||||||
|
|
||||||
|
defined("ABSPATH") || exit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security + performance hardening toggles (Settings > Security & performance).
|
||||||
|
*
|
||||||
|
* Each feature is gated on its own setting and wired here by adding/removing
|
||||||
|
* core hooks — no output is buffered or rewritten, so anything left off
|
||||||
|
* behaves exactly like stock WordPress. Settings are read once at construct
|
||||||
|
* time (plugins_loaded), the same pattern the rest of the plugin uses.
|
||||||
|
*/
|
||||||
|
class Security
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
if (Settings::get("disable_xmlrpc")) {
|
||||||
|
self::disable_xmlrpc();
|
||||||
|
}
|
||||||
|
if (Settings::get("disable_comments")) {
|
||||||
|
self::disable_comments();
|
||||||
|
}
|
||||||
|
if (Settings::get("remove_head_junk")) {
|
||||||
|
self::clean_head();
|
||||||
|
}
|
||||||
|
if (Settings::get("disable_emojis")) {
|
||||||
|
self::disable_emojis();
|
||||||
|
}
|
||||||
|
if (Settings::get("disable_oembed")) {
|
||||||
|
self::disable_oembed();
|
||||||
|
}
|
||||||
|
|
||||||
|
$heartbeat = Settings::get("heartbeat_mode", "default");
|
||||||
|
if ($heartbeat === "disabled") {
|
||||||
|
add_action("init", function () {
|
||||||
|
wp_deregister_script("heartbeat");
|
||||||
|
}, 1);
|
||||||
|
} elseif ($heartbeat === "slow") {
|
||||||
|
add_filter("heartbeat_settings", function ($settings) {
|
||||||
|
$settings["interval"] = 60;
|
||||||
|
return $settings;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function disable_xmlrpc()
|
||||||
|
{
|
||||||
|
add_filter("xmlrpc_enabled", "__return_false");
|
||||||
|
// Drop the X-Pingback header that advertises the endpoint.
|
||||||
|
add_filter("wp_headers", function ($headers) {
|
||||||
|
unset($headers["X-Pingback"]);
|
||||||
|
return $headers;
|
||||||
|
});
|
||||||
|
add_filter("pings_open", "__return_false", 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function disable_comments()
|
||||||
|
{
|
||||||
|
// Front end: closed everywhere, and existing comments never render.
|
||||||
|
add_filter("comments_open", "__return_false", 20);
|
||||||
|
add_filter("pings_open", "__return_false", 20);
|
||||||
|
add_filter("comments_array", "__return_empty_array", 20);
|
||||||
|
|
||||||
|
// Strip comment support from every post type.
|
||||||
|
add_action("init", function () {
|
||||||
|
foreach (get_post_types() as $post_type) {
|
||||||
|
if (post_type_supports($post_type, "comments")) {
|
||||||
|
remove_post_type_support($post_type, "comments");
|
||||||
|
remove_post_type_support($post_type, "trackbacks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// Admin: remove the Comments menu, the dashboard widget, and the toolbar
|
||||||
|
// bubble so there's no dangling entry point.
|
||||||
|
add_action("admin_menu", function () {
|
||||||
|
remove_menu_page("edit-comments.php");
|
||||||
|
});
|
||||||
|
add_action("wp_dashboard_setup", function () {
|
||||||
|
remove_meta_box("dashboard_recent_comments", "dashboard", "normal");
|
||||||
|
});
|
||||||
|
add_action("admin_bar_menu", function ($bar) {
|
||||||
|
$bar->remove_node("comments");
|
||||||
|
}, 999);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function clean_head()
|
||||||
|
{
|
||||||
|
remove_action("wp_head", "rsd_link");
|
||||||
|
remove_action("wp_head", "wlwmanifest_link");
|
||||||
|
remove_action("wp_head", "wp_generator");
|
||||||
|
remove_action("wp_head", "wp_shortlink_wp_head");
|
||||||
|
add_filter("the_generator", "__return_empty_string");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function disable_emojis()
|
||||||
|
{
|
||||||
|
remove_action("wp_head", "print_emoji_detection_script", 7);
|
||||||
|
remove_action("admin_print_scripts", "print_emoji_detection_script");
|
||||||
|
remove_action("wp_print_styles", "print_emoji_styles");
|
||||||
|
remove_action("admin_print_styles", "print_emoji_styles");
|
||||||
|
remove_filter("the_content_feed", "wp_staticize_emoji");
|
||||||
|
remove_filter("comment_text_rss", "wp_staticize_emoji");
|
||||||
|
remove_filter("wp_mail", "wp_staticize_emoji_for_email");
|
||||||
|
add_filter("tiny_mce_plugins", function ($plugins) {
|
||||||
|
return is_array($plugins) ? array_diff($plugins, ["wpemoji"]) : [];
|
||||||
|
});
|
||||||
|
// Drop the s.w.org DNS-prefetch the emoji script adds.
|
||||||
|
add_filter("wp_resource_hints", function ($hints, $relation_type) {
|
||||||
|
if ($relation_type === "dns-prefetch") {
|
||||||
|
$emoji_svg = apply_filters("emoji_svg_url", "https://s.w.org/images/core/emoji/");
|
||||||
|
$hints = array_filter($hints, function ($h) use ($emoji_svg) {
|
||||||
|
return strpos((string) $h, $emoji_svg) === false && strpos((string) $h, "s.w.org") === false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return $hints;
|
||||||
|
}, 10, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function disable_oembed()
|
||||||
|
{
|
||||||
|
// Core registers these on wp_head at a non-default priority (the
|
||||||
|
// discovery links sit at priority 4, not 10), so match whatever priority
|
||||||
|
// they're actually hooked at rather than assuming the default.
|
||||||
|
self::remove_wp_head_action("wp_oembed_add_discovery_links");
|
||||||
|
self::remove_wp_head_action("wp_oembed_add_host_js");
|
||||||
|
add_filter("embed_oembed_discover", "__return_false");
|
||||||
|
remove_action("rest_api_init", "wp_oembed_register_route");
|
||||||
|
// Stop the front-end wp-embed.min.js from loading.
|
||||||
|
add_action("wp_footer", function () {
|
||||||
|
wp_dequeue_script("wp-embed");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a wp_head callback at whatever priority (or priorities) it's
|
||||||
|
* registered at — core hooks the oEmbed discovery links at a non-default
|
||||||
|
* priority, and it can end up registered at more than one, so loop until
|
||||||
|
* none remain (bounded, so a stubborn callback can't spin forever).
|
||||||
|
*/
|
||||||
|
private static function remove_wp_head_action($function)
|
||||||
|
{
|
||||||
|
$guard = 0;
|
||||||
|
while (($priority = has_action("wp_head", $function)) !== false && $guard++ < 20) {
|
||||||
|
remove_action("wp_head", $function, $priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+2
-342
@@ -1,22 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "aurora-admin-app",
|
"name": "aurora-admin-app",
|
||||||
"version": "2.16.0",
|
"version": "3.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "aurora-admin-app",
|
"name": "aurora-admin-app",
|
||||||
"version": "2.16.0",
|
"version": "3.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
|
||||||
"@codemirror/lang-html": "^6.4.11",
|
|
||||||
"@codemirror/lang-javascript": "^6.2.5",
|
|
||||||
"@codemirror/lang-json": "^6.0.2",
|
|
||||||
"@codemirror/lang-markdown": "^6.5.0",
|
|
||||||
"@codemirror/lang-php": "^6.0.2",
|
|
||||||
"@codemirror/lang-sql": "^6.10.0",
|
|
||||||
"@codemirror/lang-xml": "^6.1.0",
|
|
||||||
"codemirror": "^6.0.2",
|
|
||||||
"vue": "^3.5.26"
|
"vue": "^3.5.26"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -70,198 +61,6 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/autocomplete": {
|
|
||||||
"version": "6.20.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz",
|
|
||||||
"integrity": "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/language": "^6.0.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.17.0",
|
|
||||||
"@lezer/common": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/commands": {
|
|
||||||
"version": "6.10.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.4.tgz",
|
|
||||||
"integrity": "sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/language": "^6.0.0",
|
|
||||||
"@codemirror/state": "^6.7.0",
|
|
||||||
"@codemirror/view": "^6.27.0",
|
|
||||||
"@lezer/common": "^1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-css": {
|
|
||||||
"version": "6.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
|
||||||
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.0.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@lezer/common": "^1.0.2",
|
|
||||||
"@lezer/css": "^1.1.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-html": {
|
|
||||||
"version": "6.4.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz",
|
|
||||||
"integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
|
||||||
"@codemirror/lang-css": "^6.0.0",
|
|
||||||
"@codemirror/lang-javascript": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.4.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.17.0",
|
|
||||||
"@lezer/common": "^1.0.0",
|
|
||||||
"@lezer/css": "^1.1.0",
|
|
||||||
"@lezer/html": "^1.3.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-javascript": {
|
|
||||||
"version": "6.2.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz",
|
|
||||||
"integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.6.0",
|
|
||||||
"@codemirror/lint": "^6.0.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.17.0",
|
|
||||||
"@lezer/common": "^1.0.0",
|
|
||||||
"@lezer/javascript": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-json": {
|
|
||||||
"version": "6.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
|
||||||
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/language": "^6.0.0",
|
|
||||||
"@lezer/json": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-markdown": {
|
|
||||||
"version": "6.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.5.0.tgz",
|
|
||||||
"integrity": "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/autocomplete": "^6.7.1",
|
|
||||||
"@codemirror/lang-html": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.3.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.0.0",
|
|
||||||
"@lezer/common": "^1.2.1",
|
|
||||||
"@lezer/markdown": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-php": {
|
|
||||||
"version": "6.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.2.tgz",
|
|
||||||
"integrity": "sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/lang-html": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.0.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@lezer/common": "^1.0.0",
|
|
||||||
"@lezer/php": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-sql": {
|
|
||||||
"version": "6.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.10.0.tgz",
|
|
||||||
"integrity": "sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.0.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@lezer/common": "^1.2.0",
|
|
||||||
"@lezer/highlight": "^1.0.0",
|
|
||||||
"@lezer/lr": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lang-xml": {
|
|
||||||
"version": "6.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz",
|
|
||||||
"integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.4.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.0.0",
|
|
||||||
"@lezer/common": "^1.0.0",
|
|
||||||
"@lezer/xml": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/language": {
|
|
||||||
"version": "6.12.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.4.tgz",
|
|
||||||
"integrity": "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.23.0",
|
|
||||||
"@lezer/common": "^1.5.0",
|
|
||||||
"@lezer/highlight": "^1.0.0",
|
|
||||||
"@lezer/lr": "^1.0.0",
|
|
||||||
"style-mod": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/lint": {
|
|
||||||
"version": "6.9.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.7.tgz",
|
|
||||||
"integrity": "sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.42.0",
|
|
||||||
"crelt": "^1.0.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/search": {
|
|
||||||
"version": "6.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.1.tgz",
|
|
||||||
"integrity": "sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.37.0",
|
|
||||||
"crelt": "^1.0.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/state": {
|
|
||||||
"version": "6.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.1.tgz",
|
|
||||||
"integrity": "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@marijn/find-cluster-break": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@codemirror/view": {
|
|
||||||
"version": "6.43.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.5.tgz",
|
|
||||||
"integrity": "sha512-7uT/vUgH6dfXWn3WqOe23KneILMvGy5wQjNMEcRXLKzziJ9NOktpW6tGoyQpwVkBgE5Gj6hKkCcsddbnkaWrOQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/state": "^6.7.0",
|
|
||||||
"crelt": "^1.0.6",
|
|
||||||
"style-mod": "^4.1.0",
|
|
||||||
"w3c-keyname": "^2.2.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.25.12",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||||
@@ -710,112 +509,6 @@
|
|||||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/common": {
|
|
||||||
"version": "1.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz",
|
|
||||||
"integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/css": {
|
|
||||||
"version": "1.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.4.tgz",
|
|
||||||
"integrity": "sha512-N+tn9tej2hPvyKgHEApMOQfHczDJCwxrRFS3SPn9QjYN+uwHvEDnCgKRrb3mxDYxRS8sKMM8fhC3+lc04Abz5Q==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.2.0",
|
|
||||||
"@lezer/highlight": "^1.0.0",
|
|
||||||
"@lezer/lr": "^1.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/highlight": {
|
|
||||||
"version": "1.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
|
||||||
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/html": {
|
|
||||||
"version": "1.3.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.13.tgz",
|
|
||||||
"integrity": "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.2.0",
|
|
||||||
"@lezer/highlight": "^1.0.0",
|
|
||||||
"@lezer/lr": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/javascript": {
|
|
||||||
"version": "1.5.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
|
|
||||||
"integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.2.0",
|
|
||||||
"@lezer/highlight": "^1.1.3",
|
|
||||||
"@lezer/lr": "^1.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/json": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.2.0",
|
|
||||||
"@lezer/highlight": "^1.0.0",
|
|
||||||
"@lezer/lr": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/lr": {
|
|
||||||
"version": "1.4.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz",
|
|
||||||
"integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/markdown": {
|
|
||||||
"version": "1.6.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.6.4.tgz",
|
|
||||||
"integrity": "sha512-N0SxazMj4k65DBfaf1azqtMZd6u7MqluP84/NZnB/io8Td9aleFmAhz9hcbvSfsxT5tdYlJ5qgv5aMJGY4zEtA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.5.0",
|
|
||||||
"@lezer/highlight": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/php": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.5.tgz",
|
|
||||||
"integrity": "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.2.0",
|
|
||||||
"@lezer/highlight": "^1.0.0",
|
|
||||||
"@lezer/lr": "^1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@lezer/xml": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@lezer/common": "^1.2.0",
|
|
||||||
"@lezer/highlight": "^1.0.0",
|
|
||||||
"@lezer/lr": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@marijn/find-cluster-break": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.62.2",
|
"version": "4.62.2",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
|
||||||
@@ -1326,27 +1019,6 @@
|
|||||||
"integrity": "sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==",
|
"integrity": "sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/codemirror": {
|
|
||||||
"version": "6.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
|
||||||
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
|
||||||
"@codemirror/commands": "^6.0.0",
|
|
||||||
"@codemirror/language": "^6.0.0",
|
|
||||||
"@codemirror/lint": "^6.0.0",
|
|
||||||
"@codemirror/search": "^6.0.0",
|
|
||||||
"@codemirror/state": "^6.0.0",
|
|
||||||
"@codemirror/view": "^6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/crelt": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||||
@@ -1574,12 +1246,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/style-mod": {
|
|
||||||
"version": "4.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
|
|
||||||
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.17",
|
"version": "0.2.17",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||||
@@ -1692,12 +1358,6 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"node_modules/w3c-keyname": {
|
|
||||||
"version": "2.2.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
|
||||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,6 @@
|
|||||||
"build": "vite build"
|
"build": "vite build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
|
||||||
"@codemirror/lang-html": "^6.4.11",
|
|
||||||
"@codemirror/lang-javascript": "^6.2.5",
|
|
||||||
"@codemirror/lang-json": "^6.0.2",
|
|
||||||
"@codemirror/lang-markdown": "^6.5.0",
|
|
||||||
"@codemirror/lang-php": "^6.0.2",
|
|
||||||
"@codemirror/lang-sql": "^6.10.0",
|
|
||||||
"@codemirror/lang-xml": "^6.1.0",
|
|
||||||
"codemirror": "^6.0.2",
|
|
||||||
"vue": "^3.5.26"
|
"vue": "^3.5.26"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import '@/shell/shell-frame.css';
|
||||||
|
import SetupWizard from '@/pages/setup-wizard/SetupWizard.vue';
|
||||||
|
|
||||||
|
const mountEl = document.getElementById('aurora-admin-setup-root');
|
||||||
|
|
||||||
|
if (mountEl) {
|
||||||
|
const data = JSON.parse(mountEl.dataset.auroraAdmin || '{}');
|
||||||
|
createApp(SetupWizard, { serverData: data }).mount(mountEl);
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@ defineEmits(['click']);
|
|||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 12px;
|
border-radius: var(--aurora-radius-md);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
.app-list-item:hover {
|
.app-list-item:hover {
|
||||||
@@ -49,7 +49,7 @@ defineEmits(['click']);
|
|||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-radius: 9px;
|
border-radius: var(--aurora-radius-md);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ const search = defineModel('search', { type: String, default: '' });
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: 16px;
|
border-radius: var(--aurora-radius-lg);
|
||||||
padding: 24px 20px;
|
padding: 24px 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ const search = defineModel('search', { type: String, default: '' });
|
|||||||
.app-list-shell__actions { display: flex; gap: 6px; align-items: center; }
|
.app-list-shell__actions { display: flex; gap: 6px; align-items: center; }
|
||||||
.app-list-shell__actions :deep(button) {
|
.app-list-shell__actions :deep(button) {
|
||||||
display: inline-flex; align-items: center; justify-content: center;
|
display: inline-flex; align-items: center; justify-content: center;
|
||||||
height: 30px; padding: 0 10px; border: none; border-radius: 7px;
|
height: 30px; padding: 0 10px; border: none; border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text-muted);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text-muted);
|
||||||
font-size: 0.75rem; font-weight: 500; cursor: pointer; gap: 6px;
|
font-size: 0.75rem; font-weight: 500; cursor: pointer; gap: 6px;
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ const search = defineModel('search', { type: String, default: '' });
|
|||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 10px; padding: 8px 12px; margin-bottom: 14px;
|
border-radius: var(--aurora-radius-md); padding: 8px 12px; margin-bottom: 14px;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
}
|
}
|
||||||
.app-list-shell__search input {
|
.app-list-shell__search input {
|
||||||
@@ -161,7 +161,7 @@ const search = defineModel('search', { type: String, default: '' });
|
|||||||
flex: 1; min-width: 0;
|
flex: 1; min-width: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: 16px;
|
border-radius: var(--aurora-radius-lg);
|
||||||
padding: 28px 32px;
|
padding: 28px 32px;
|
||||||
min-height: 480px;
|
min-height: 480px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -174,7 +174,7 @@ const search = defineModel('search', { type: String, default: '' });
|
|||||||
text-align: center; gap: 6px;
|
text-align: center; gap: 6px;
|
||||||
}
|
}
|
||||||
.app-list-shell__empty-icon {
|
.app-list-shell__empty-icon {
|
||||||
width: 56px; height: 56px; border-radius: 14px;
|
width: 56px; height: 56px; border-radius: var(--aurora-radius-md);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text-muted);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text-muted);
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-size: 22px; margin-bottom: 10px;
|
font-size: 22px; margin-bottom: 10px;
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ const formatDate = (s) => (s ? new Date(s.replace(' ', 'T')).toLocaleString() :
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.activity-log__select {
|
.activity-log__select {
|
||||||
padding: 5px 10px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
padding: 5px 10px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.75rem;
|
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
.activity-detail h2 { margin: 0 0 16px; font-size: 1.1rem; color: var(--aurora-text); }
|
.activity-detail h2 { margin: 0 0 16px; font-size: 1.1rem; color: var(--aurora-text); }
|
||||||
@@ -148,6 +148,6 @@ const formatDate = (s) => (s ? new Date(s.replace(' ', 'T')).toLocaleString() :
|
|||||||
.activity-detail dd { margin: 0; color: var(--aurora-text); }
|
.activity-detail dd { margin: 0; color: var(--aurora-text); }
|
||||||
.activity-detail pre {
|
.activity-detail pre {
|
||||||
margin-top: 18px; padding: 12px; background: var(--aurora-bg-subtle);
|
margin-top: 18px; padding: 12px; background: var(--aurora-bg-subtle);
|
||||||
border-radius: 8px; font-size: 0.75rem; overflow-x: auto; color: var(--aurora-text);
|
border-radius: var(--aurora-radius-sm); font-size: 0.75rem; overflow-x: auto; color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -190,11 +190,11 @@ const remove = async () => {
|
|||||||
.notice-editor__row { display: flex; gap: 10px; }
|
.notice-editor__row { display: flex; gap: 10px; }
|
||||||
.notice-editor__title {
|
.notice-editor__title {
|
||||||
flex: 1; font-size: 1.05rem; font-weight: 700; padding: 8px 10px;
|
flex: 1; font-size: 1.05rem; font-weight: 700; padding: 8px 10px;
|
||||||
border: 1px solid var(--aurora-border); border-radius: 8px;
|
border: 1px solid var(--aurora-border); border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.notice-editor select, .notice-editor input[type='text'], .notice-editor textarea {
|
.notice-editor select, .notice-editor input[type='text'], .notice-editor textarea {
|
||||||
padding: 8px 10px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
padding: 8px 10px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.8125rem;
|
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.8125rem;
|
||||||
font-family: inherit; width: 100%; box-sizing: border-box;
|
font-family: inherit; width: 100%; box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -208,7 +208,7 @@ const remove = async () => {
|
|||||||
.notice-editor__toggles label { display: flex; align-items: center; gap: 6px; }
|
.notice-editor__toggles label { display: flex; align-items: center; gap: 6px; }
|
||||||
.notice-editor__actions { display: flex; justify-content: flex-end; gap: 8px; }
|
.notice-editor__actions { display: flex; justify-content: flex-end; gap: 8px; }
|
||||||
.notice-editor__actions button {
|
.notice-editor__actions button {
|
||||||
border: none; border-radius: 8px; padding: 9px 18px; font-size: 0.875rem; cursor: pointer;
|
border: none; border-radius: var(--aurora-radius-sm); padding: 9px 18px; font-size: 0.875rem; cursor: pointer;
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.notice-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
|
.notice-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ const send = async () => {
|
|||||||
.bug-report-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
.bug-report-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
||||||
.bug-report-page__sub { margin: 8px 0 0; font-size: 0.875rem; color: var(--aurora-text-muted); }
|
.bug-report-page__sub { margin: 8px 0 0; font-size: 0.875rem; color: var(--aurora-text-muted); }
|
||||||
|
|
||||||
.bug-report-notice { padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.875rem; }
|
.bug-report-notice { padding: 10px 14px; border-radius: var(--aurora-radius-sm); margin-bottom: 16px; font-size: 0.875rem; }
|
||||||
.bug-report-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
.bug-report-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
||||||
.bug-report-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
.bug-report-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
||||||
|
|
||||||
@@ -106,14 +106,14 @@ const send = async () => {
|
|||||||
.bug-report-field { display: flex; flex-direction: column; gap: 6px; }
|
.bug-report-field { display: flex; flex-direction: column; gap: 6px; }
|
||||||
.bug-report-field span { font-size: 0.8125rem; font-weight: 600; color: var(--aurora-text); }
|
.bug-report-field span { font-size: 0.8125rem; font-weight: 600; color: var(--aurora-text); }
|
||||||
.bug-report-field textarea {
|
.bug-report-field textarea {
|
||||||
padding: 10px 12px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
padding: 10px 12px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.875rem;
|
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.875rem;
|
||||||
font-family: inherit; resize: vertical;
|
font-family: inherit; resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bug-report-diagnostics {
|
.bug-report-diagnostics {
|
||||||
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
||||||
border-radius: 10px; padding: 14px 16px;
|
border-radius: var(--aurora-radius-md); padding: 14px 16px;
|
||||||
}
|
}
|
||||||
.bug-report-diagnostics h2 {
|
.bug-report-diagnostics h2 {
|
||||||
margin: 0 0 10px; font-size: 0.75rem; text-transform: uppercase;
|
margin: 0 0 10px; font-size: 0.75rem; text-transform: uppercase;
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ const rowRange = computed(() => {
|
|||||||
width: min(320px, 100%);
|
width: min(320px, 100%);
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -423,7 +423,7 @@ const rowRange = computed(() => {
|
|||||||
width: 42px;
|
width: 42px;
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -451,7 +451,7 @@ const rowRange = computed(() => {
|
|||||||
.comments-notice {
|
.comments-notice {
|
||||||
margin: 0 0 12px;
|
margin: 0 0 12px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
@@ -460,7 +460,7 @@ const rowRange = computed(() => {
|
|||||||
.comments-table {
|
.comments-table {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
}
|
}
|
||||||
.comments-table__head,
|
.comments-table__head,
|
||||||
@@ -636,7 +636,7 @@ const rowRange = computed(() => {
|
|||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ onMounted(() => reload(range.value[0], range.value[1]));
|
|||||||
background: var(--aurora-card-bg);
|
background: var(--aurora-card-bg);
|
||||||
border: 1px solid var(--aurora-card-border);
|
border: 1px solid var(--aurora-card-border);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -186,7 +186,7 @@ onMounted(() => reload(range.value[0], range.value[1]));
|
|||||||
position: absolute; right: 0; top: calc(100% + 6px);
|
position: absolute; right: 0; top: calc(100% + 6px);
|
||||||
background: var(--aurora-card-bg);
|
background: var(--aurora-card-bg);
|
||||||
border: 1px solid var(--aurora-card-border);
|
border: 1px solid var(--aurora-card-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
@@ -195,14 +195,14 @@ onMounted(() => reload(range.value[0], range.value[1]));
|
|||||||
.dash__presets button {
|
.dash__presets button {
|
||||||
display: block; width: 100%; text-align: left;
|
display: block; width: 100%; text-align: left;
|
||||||
background: none; border: none; color: var(--aurora-text);
|
background: none; border: none; color: var(--aurora-text);
|
||||||
padding: 8px 10px; border-radius: 6px; cursor: pointer; font-size: 0.8125rem;
|
padding: 8px 10px; border-radius: var(--aurora-radius-sm); cursor: pointer; font-size: 0.8125rem;
|
||||||
}
|
}
|
||||||
.dash__presets button:hover { background: var(--aurora-bg-subtle); }
|
.dash__presets button:hover { background: var(--aurora-bg-subtle); }
|
||||||
.dash__tabs {
|
.dash__tabs {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ onMounted(() => reload(range.value[0], range.value[1]));
|
|||||||
}
|
}
|
||||||
.dash__tab {
|
.dash__tab {
|
||||||
border: none; background: none; cursor: pointer;
|
border: none; background: none; cursor: pointer;
|
||||||
padding: 6px 16px; border-radius: 8px;
|
padding: 6px 16px; border-radius: var(--aurora-radius-sm);
|
||||||
font-size: 0.8125rem; font-weight: 500;
|
font-size: 0.8125rem; font-weight: 500;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ defineProps({ data: { type: Object, default: () => ({}) } });
|
|||||||
.ma__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
.ma__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||||
.ma__box {
|
.ma__box {
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border-radius: 14px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ const onDayClick = (cell) => {
|
|||||||
border: 1px solid var(--aurora-card-border);
|
border: 1px solid var(--aurora-card-border);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ const onDayClick = (cell) => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%; height: 100%;
|
width: 100%; height: 100%;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
border: 1px solid var(--aurora-card-border);
|
border: 1px solid var(--aurora-card-border);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -156,7 +156,7 @@ const onDayClick = (cell) => {
|
|||||||
background: var(--aurora-card-bg, #1f1f23);
|
background: var(--aurora-card-bg, #1f1f23);
|
||||||
color: var(--aurora-text, #f4f4f5);
|
color: var(--aurora-text, #f4f4f5);
|
||||||
border: 1px solid var(--aurora-border, #2e2e33);
|
border: 1px solid var(--aurora-border, #2e2e33);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 12px 18px;
|
padding: 12px 18px;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ defineProps({ data: { type: Object, default: () => ({}) } });
|
|||||||
.sh__versions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 14px; }
|
.sh__versions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 14px; }
|
||||||
.sh__ver {
|
.sh__ver {
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border-radius: 12px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
}
|
}
|
||||||
.sh__ver-label { font-size: 0.6875rem; color: var(--aurora-text-muted); }
|
.sh__ver-label { font-size: 0.6875rem; color: var(--aurora-text-muted); }
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ defineProps({
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* Deeper than the generic --aurora-card-bg — the Dashboard is now
|
/* Deeper than the generic --aurora-card-bg — the Dashboard is now
|
||||||
wrapped in its own frame (windowChrome.js's .aurora-dashboard-frame,
|
wrapped in its own frame (dashboardFrame.js's .aurora-dashboard-frame,
|
||||||
using --aurora-frame-bg), and that's close in tone to --aurora-card-bg
|
using --aurora-frame-bg), and that's close in tone to --aurora-card-bg
|
||||||
for most presets, so cards would nearly disappear into it otherwise. */
|
for most presets, so cards would nearly disappear into it otherwise. */
|
||||||
background: var(--aurora-card-bg-deep, var(--aurora-card-bg));
|
background: var(--aurora-card-bg-deep, var(--aurora-card-bg));
|
||||||
border: 1px solid var(--aurora-card-border);
|
border: 1px solid var(--aurora-card-border);
|
||||||
border-radius: 20px;
|
border-radius: var(--aurora-radius-lg);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ defineProps({
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.pbar {
|
.pbar {
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border-radius: 12px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
}
|
}
|
||||||
.pbar__top {
|
.pbar__top {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ defineProps({
|
|||||||
}
|
}
|
||||||
.statrow--boxed {
|
.statrow--boxed {
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border-radius: 14px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 16px 8px;
|
padding: 16px 8px;
|
||||||
}
|
}
|
||||||
.statrow__value {
|
.statrow__value {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ const clearDone = () => {
|
|||||||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||||
gap: 10px; padding: 48px 24px; text-align: center; cursor: pointer;
|
gap: 10px; padding: 48px 24px; text-align: center; cursor: pointer;
|
||||||
border: 2px dashed var(--aurora-border);
|
border: 2px dashed var(--aurora-border);
|
||||||
border-radius: 14px;
|
border-radius: var(--aurora-radius-md);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
transition: border-color 0.15s, color 0.15s;
|
transition: border-color 0.15s, color 0.15s;
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ const clearDone = () => {
|
|||||||
|
|
||||||
.media-upload-item {
|
.media-upload-item {
|
||||||
display: flex; align-items: center; justify-content: space-between;
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
padding: 10px 14px; border-radius: 8px;
|
padding: 10px 14px; border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
margin-bottom: 6px; font-size: 0.875rem;
|
margin-bottom: 6px; font-size: 0.875rem;
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ const typeIcon = (mimeType) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-accent);
|
background: var(--aurora-accent);
|
||||||
color: var(--aurora-accent-text);
|
color: var(--aurora-accent-text);
|
||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
@@ -529,7 +529,7 @@ const typeIcon = (mimeType) => {
|
|||||||
width: min(320px, 100%);
|
width: min(320px, 100%);
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -554,7 +554,7 @@ const typeIcon = (mimeType) => {
|
|||||||
width: 42px;
|
width: 42px;
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -581,7 +581,7 @@ const typeIcon = (mimeType) => {
|
|||||||
.media-notice {
|
.media-notice {
|
||||||
margin: 0 0 12px;
|
margin: 0 0 12px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
@@ -590,7 +590,7 @@ const typeIcon = (mimeType) => {
|
|||||||
.media-grid__empty {
|
.media-grid__empty {
|
||||||
padding: 60px 18px;
|
padding: 60px 18px;
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
@@ -603,7 +603,7 @@ const typeIcon = (mimeType) => {
|
|||||||
}
|
}
|
||||||
.media-card {
|
.media-card {
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -688,7 +688,7 @@ const typeIcon = (mimeType) => {
|
|||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -733,7 +733,7 @@ const typeIcon = (mimeType) => {
|
|||||||
width: 220px;
|
width: 220px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
}
|
}
|
||||||
.media-page__main {
|
.media-page__main {
|
||||||
@@ -753,7 +753,7 @@ const typeIcon = (mimeType) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: none;
|
background: none;
|
||||||
padding: 6px 6px;
|
padding: 6px 6px;
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
@@ -815,7 +815,7 @@ const typeIcon = (mimeType) => {
|
|||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
@@ -826,7 +826,7 @@ const typeIcon = (mimeType) => {
|
|||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ const runFromMenu = (fn) => {
|
|||||||
.mf-tree { list-style: none; margin: 0; padding-left: 14px; }
|
.mf-tree { list-style: none; margin: 0; padding-left: 14px; }
|
||||||
.mf-tree:first-of-type { padding-left: 0; }
|
.mf-tree:first-of-type { padding-left: 0; }
|
||||||
.mf-tree__row {
|
.mf-tree__row {
|
||||||
display: flex; align-items: center; gap: 2px; border-radius: 6px;
|
display: flex; align-items: center; gap: 2px; border-radius: var(--aurora-radius-sm);
|
||||||
}
|
}
|
||||||
.mf-tree__row:hover { background: var(--aurora-bg-subtle); }
|
.mf-tree__row:hover { background: var(--aurora-bg-subtle); }
|
||||||
.mf-tree__row--active { background: var(--aurora-accent-soft); }
|
.mf-tree__row--active { background: var(--aurora-accent-soft); }
|
||||||
@@ -163,7 +163,7 @@ const runFromMenu = (fn) => {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ const runFromMenu = (fn) => {
|
|||||||
padding: 7px 10px;
|
padding: 7px 10px;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|||||||
@@ -225,11 +225,11 @@ const toggleRole = (slug) => {
|
|||||||
.menu-editor__row { display: flex; gap: 10px; }
|
.menu-editor__row { display: flex; gap: 10px; }
|
||||||
.menu-editor__name {
|
.menu-editor__name {
|
||||||
flex: 1; font-size: 1.1rem; font-weight: 700; padding: 8px 10px;
|
flex: 1; font-size: 1.1rem; font-weight: 700; padding: 8px 10px;
|
||||||
border: 1px solid var(--aurora-border); border-radius: 8px;
|
border: 1px solid var(--aurora-border); border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.menu-editor__status {
|
.menu-editor__status {
|
||||||
padding: 8px 10px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
padding: 8px 10px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.menu-editor__section h3 {
|
.menu-editor__section h3 {
|
||||||
@@ -244,13 +244,13 @@ const toggleRole = (slug) => {
|
|||||||
border-bottom: 1px solid var(--aurora-frame-border);
|
border-bottom: 1px solid var(--aurora-frame-border);
|
||||||
}
|
}
|
||||||
.menu-editor__item input[type='text'] {
|
.menu-editor__item input[type='text'] {
|
||||||
flex: 1; padding: 6px 8px; border-radius: 6px; border: 1px solid var(--aurora-border);
|
flex: 1; padding: 6px 8px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.8125rem;
|
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.8125rem;
|
||||||
}
|
}
|
||||||
.menu-editor__hide { display: flex; align-items: center; gap: 4px; font-size: 0.75rem; color: var(--aurora-text-muted); }
|
.menu-editor__hide { display: flex; align-items: center; gap: 4px; font-size: 0.75rem; color: var(--aurora-text-muted); }
|
||||||
.menu-editor__actions { display: flex; justify-content: flex-end; gap: 8px; }
|
.menu-editor__actions { display: flex; justify-content: flex-end; gap: 8px; }
|
||||||
.menu-editor__actions button {
|
.menu-editor__actions button {
|
||||||
border: none; border-radius: 8px; padding: 9px 18px; font-size: 0.875rem; cursor: pointer;
|
border: none; border-radius: var(--aurora-radius-sm); padding: 9px 18px; font-size: 0.875rem; cursor: pointer;
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.menu-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
|
.menu-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ const save = async () => {
|
|||||||
.native-settings__saved { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
.native-settings__saved { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
||||||
.native-settings__save {
|
.native-settings__save {
|
||||||
background: var(--aurora-accent); color: #fff; border: none;
|
background: var(--aurora-accent); color: #fff; border: none;
|
||||||
border-radius: 9px; padding: 9px 20px; font-size: 0.875rem; font-weight: 500; cursor: pointer;
|
border-radius: var(--aurora-radius-md); padding: 9px 20px; font-size: 0.875rem; font-weight: 500; cursor: pointer;
|
||||||
}
|
}
|
||||||
.native-settings__save:disabled { opacity: 0.6; cursor: default; }
|
.native-settings__save:disabled { opacity: 0.6; cursor: default; }
|
||||||
.native-settings__fields > :last-child { border-bottom: none; }
|
.native-settings__fields > :last-child { border-bottom: none; }
|
||||||
@@ -210,6 +210,6 @@ const save = async () => {
|
|||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 5px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -361,21 +361,21 @@ const assignLocation = async (slug, menuId) => {
|
|||||||
}
|
}
|
||||||
.nav-menus-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
.nav-menus-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
||||||
|
|
||||||
.nav-menus-notice { padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.875rem; }
|
.nav-menus-notice { padding: 10px 14px; border-radius: var(--aurora-radius-sm); margin-bottom: 16px; font-size: 0.875rem; }
|
||||||
.nav-menus-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
.nav-menus-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
||||||
.nav-menus-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
.nav-menus-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
||||||
|
|
||||||
.nav-menus-layout { display: grid; grid-template-columns: 260px 300px 1fr; gap: 20px; align-items: start; }
|
.nav-menus-layout { display: grid; grid-template-columns: 260px 300px 1fr; gap: 20px; align-items: start; }
|
||||||
.nav-menus-side, .nav-menus-add, .nav-menus-structure {
|
.nav-menus-side, .nav-menus-add, .nav-menus-structure {
|
||||||
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
||||||
border-radius: 14px; padding: 18px;
|
border-radius: var(--aurora-radius-md); padding: 18px;
|
||||||
}
|
}
|
||||||
.nav-menus-side h2, .nav-menus-add h2, .nav-menus-structure h2 {
|
.nav-menus-side h2, .nav-menus-add h2, .nav-menus-structure h2 {
|
||||||
font-size: 0.9375rem; margin: 0 0 10px; color: var(--aurora-text);
|
font-size: 0.9375rem; margin: 0 0 10px; color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.nav-menus-list { list-style: none; margin: 0 0 14px; padding: 0; }
|
.nav-menus-list { list-style: none; margin: 0 0 14px; padding: 0; }
|
||||||
.nav-menus-list__item {
|
.nav-menus-list__item {
|
||||||
width: 100%; text-align: left; padding: 8px 10px; border-radius: 8px;
|
width: 100%; text-align: left; padding: 8px 10px; border-radius: var(--aurora-radius-sm);
|
||||||
border: none; background: none; color: var(--aurora-text-muted); cursor: pointer;
|
border: none; background: none; color: var(--aurora-text-muted); cursor: pointer;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
@@ -385,7 +385,7 @@ const assignLocation = async (slug, menuId) => {
|
|||||||
|
|
||||||
.nav-menus-create { display: flex; gap: 6px; margin-bottom: 20px; }
|
.nav-menus-create { display: flex; gap: 6px; margin-bottom: 20px; }
|
||||||
.nav-menus-create input {
|
.nav-menus-create input {
|
||||||
flex: 1; padding: 7px 10px; border-radius: 7px; border: 1px solid var(--aurora-border);
|
flex: 1; padding: 7px 10px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.8125rem;
|
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.8125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,20 +393,20 @@ const assignLocation = async (slug, menuId) => {
|
|||||||
.nav-menus-location label { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
.nav-menus-location label { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
||||||
.nav-menus-location select,
|
.nav-menus-location select,
|
||||||
.nav-menus-add__custom input {
|
.nav-menus-add__custom input {
|
||||||
padding: 7px 10px; border-radius: 7px; border: 1px solid var(--aurora-border);
|
padding: 7px 10px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.8125rem;
|
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.8125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-menus-add__tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
|
.nav-menus-add__tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
|
||||||
.nav-menus-add__tabs button {
|
.nav-menus-add__tabs button {
|
||||||
padding: 6px 10px; border-radius: 7px; border: 1px solid var(--aurora-border);
|
padding: 6px 10px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg); color: var(--aurora-text-muted); font-size: 0.75rem; cursor: pointer;
|
background: var(--aurora-bg); color: var(--aurora-text-muted); font-size: 0.75rem; cursor: pointer;
|
||||||
}
|
}
|
||||||
.nav-menus-add__tabs button.is-active { background: var(--aurora-accent-soft); color: var(--aurora-accent); border-color: transparent; }
|
.nav-menus-add__tabs button.is-active { background: var(--aurora-accent-soft); color: var(--aurora-accent); border-color: transparent; }
|
||||||
|
|
||||||
.nav-menus-add__list { max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
|
.nav-menus-add__list { max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
|
||||||
.nav-menus-add__row {
|
.nav-menus-add__row {
|
||||||
display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px;
|
display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: var(--aurora-radius-sm);
|
||||||
font-size: 0.8125rem; color: var(--aurora-text);
|
font-size: 0.8125rem; color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.nav-menus-add__row:hover { background: var(--aurora-bg); }
|
.nav-menus-add__row:hover { background: var(--aurora-bg); }
|
||||||
@@ -417,14 +417,14 @@ const assignLocation = async (slug, menuId) => {
|
|||||||
.nav-menus-structure__head { display: flex; align-items: center; justify-content: space-between; }
|
.nav-menus-structure__head { display: flex; align-items: center; justify-content: space-between; }
|
||||||
.nav-menus-item {
|
.nav-menus-item {
|
||||||
display: flex; align-items: center; justify-content: space-between;
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
padding: 8px 12px; border-radius: 8px; margin-bottom: 4px;
|
padding: 8px 12px; border-radius: var(--aurora-radius-sm); margin-bottom: 4px;
|
||||||
background: var(--aurora-bg); border: 1px solid var(--aurora-border);
|
background: var(--aurora-bg); border: 1px solid var(--aurora-border);
|
||||||
font-size: 0.8125rem; color: var(--aurora-text);
|
font-size: 0.8125rem; color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.nav-menus-item__actions { display: flex; gap: 2px; }
|
.nav-menus-item__actions { display: flex; gap: 2px; }
|
||||||
.nav-menus-item__actions button {
|
.nav-menus-item__actions button {
|
||||||
border: none; background: none; color: var(--aurora-text-muted); cursor: pointer;
|
border: none; background: none; color: var(--aurora-text-muted); cursor: pointer;
|
||||||
width: 26px; height: 26px; border-radius: 6px; display: inline-flex; align-items: center; justify-content: center;
|
width: 26px; height: 26px; border-radius: var(--aurora-radius-sm); display: inline-flex; align-items: center; justify-content: center;
|
||||||
}
|
}
|
||||||
.nav-menus-item__actions button:hover { background: var(--aurora-bg-subtle); color: var(--aurora-text); }
|
.nav-menus-item__actions button:hover { background: var(--aurora-bg-subtle); color: var(--aurora-text); }
|
||||||
.nav-menus-item__actions button:disabled { opacity: 0.35; cursor: default; }
|
.nav-menus-item__actions button:disabled { opacity: 0.35; cursor: default; }
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ const rowRange = computed(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-accent);
|
background: var(--aurora-accent);
|
||||||
color: var(--aurora-accent-text);
|
color: var(--aurora-accent-text);
|
||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
@@ -390,7 +390,7 @@ const rowRange = computed(() => {
|
|||||||
width: min(320px, 100%);
|
width: min(320px, 100%);
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -415,7 +415,7 @@ const rowRange = computed(() => {
|
|||||||
width: 42px;
|
width: 42px;
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -442,7 +442,7 @@ const rowRange = computed(() => {
|
|||||||
.pages-notice {
|
.pages-notice {
|
||||||
margin: 0 0 12px;
|
margin: 0 0 12px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
@@ -451,7 +451,7 @@ const rowRange = computed(() => {
|
|||||||
.pages-table {
|
.pages-table {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
}
|
}
|
||||||
.pages-table__head,
|
.pages-table__head,
|
||||||
@@ -559,7 +559,7 @@ const rowRange = computed(() => {
|
|||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ const versionLine = (plugin) => {
|
|||||||
width: min(320px, 100%);
|
width: min(320px, 100%);
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -388,7 +388,7 @@ const versionLine = (plugin) => {
|
|||||||
.primary-button,
|
.primary-button,
|
||||||
.icon-button {
|
.icon-button {
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
@@ -439,7 +439,7 @@ const versionLine = (plugin) => {
|
|||||||
.plugins-notice {
|
.plugins-notice {
|
||||||
margin: 0 0 12px;
|
margin: 0 0 12px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-weight: 750;
|
font-weight: 750;
|
||||||
}
|
}
|
||||||
@@ -454,7 +454,7 @@ const versionLine = (plugin) => {
|
|||||||
.plugins-table {
|
.plugins-table {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
@@ -505,7 +505,7 @@ const versionLine = (plugin) => {
|
|||||||
.plugin-row__mark {
|
.plugin-row__mark {
|
||||||
width: 46px;
|
width: 46px;
|
||||||
height: 46px;
|
height: 46px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ const rowRange = computed(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-accent);
|
background: var(--aurora-accent);
|
||||||
color: var(--aurora-accent-text);
|
color: var(--aurora-accent-text);
|
||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
@@ -392,7 +392,7 @@ const rowRange = computed(() => {
|
|||||||
width: min(320px, 100%);
|
width: min(320px, 100%);
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -417,7 +417,7 @@ const rowRange = computed(() => {
|
|||||||
width: 42px;
|
width: 42px;
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -444,7 +444,7 @@ const rowRange = computed(() => {
|
|||||||
.posts-notice {
|
.posts-notice {
|
||||||
margin: 0 0 12px;
|
margin: 0 0 12px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
@@ -453,7 +453,7 @@ const rowRange = computed(() => {
|
|||||||
.posts-table {
|
.posts-table {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
}
|
}
|
||||||
.posts-table__head,
|
.posts-table__head,
|
||||||
@@ -561,7 +561,7 @@ const rowRange = computed(() => {
|
|||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ const changePassword = async () => {
|
|||||||
.profile-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
.profile-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
||||||
.profile-empty { color: var(--aurora-text-muted); font-size: 0.8125rem; }
|
.profile-empty { color: var(--aurora-text-muted); font-size: 0.8125rem; }
|
||||||
|
|
||||||
.profile-notice { padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.875rem; }
|
.profile-notice { padding: 10px 14px; border-radius: var(--aurora-radius-sm); margin-bottom: 16px; font-size: 0.875rem; }
|
||||||
.profile-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
.profile-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
||||||
.profile-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
.profile-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
||||||
.profile-notice--info { background: var(--aurora-bg-subtle); color: var(--aurora-text-muted); }
|
.profile-notice--info { background: var(--aurora-bg-subtle); color: var(--aurora-text-muted); }
|
||||||
@@ -182,7 +182,7 @@ const changePassword = async () => {
|
|||||||
display: flex; flex-direction: column; gap: 18px;
|
display: flex; flex-direction: column; gap: 18px;
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 14px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ const changePassword = async () => {
|
|||||||
.profile-field span { font-size: 0.8125rem; font-weight: 600; color: var(--aurora-text); }
|
.profile-field span { font-size: 0.8125rem; font-weight: 600; color: var(--aurora-text); }
|
||||||
.profile-field input,
|
.profile-field input,
|
||||||
.profile-field textarea {
|
.profile-field textarea {
|
||||||
padding: 9px 12px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
padding: 9px 12px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.875rem;
|
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.875rem;
|
||||||
font-family: inherit; resize: vertical;
|
font-family: inherit; resize: vertical;
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ const changePassword = async () => {
|
|||||||
.profile-password h2 { margin: 0 0 4px; font-size: 0.9375rem; color: var(--aurora-text); }
|
.profile-password h2 { margin: 0 0 4px; font-size: 0.9375rem; color: var(--aurora-text); }
|
||||||
.profile-password__row { display: flex; gap: 8px; }
|
.profile-password__row { display: flex; gap: 8px; }
|
||||||
.profile-password__row input {
|
.profile-password__row input {
|
||||||
flex: 1; padding: 9px 12px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
flex: 1; padding: 9px 12px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.875rem;
|
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ const remove = async () => {
|
|||||||
.role-editor { display: flex; flex-direction: column; gap: 18px; }
|
.role-editor { display: flex; flex-direction: column; gap: 18px; }
|
||||||
.role-editor__row { display: flex; gap: 10px; }
|
.role-editor__row { display: flex; gap: 10px; }
|
||||||
.role-editor__slug, .role-editor__name {
|
.role-editor__slug, .role-editor__name {
|
||||||
padding: 8px 10px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
padding: 8px 10px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.875rem;
|
background: var(--aurora-bg-subtle); color: var(--aurora-text); font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
.role-editor__name { flex: 1; font-weight: 700; }
|
.role-editor__name { flex: 1; font-weight: 700; }
|
||||||
@@ -225,7 +225,7 @@ const remove = async () => {
|
|||||||
z-index: 20;
|
z-index: 20;
|
||||||
width: 260px;
|
width: 260px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
@@ -246,7 +246,7 @@ const remove = async () => {
|
|||||||
}
|
}
|
||||||
.role-editor__actions { display: flex; justify-content: flex-end; gap: 8px; }
|
.role-editor__actions { display: flex; justify-content: flex-end; gap: 8px; }
|
||||||
.role-editor__actions button {
|
.role-editor__actions button {
|
||||||
border: none; border-radius: 8px; padding: 9px 18px; font-size: 0.875rem; cursor: pointer;
|
border: none; border-radius: var(--aurora-radius-sm); padding: 9px 18px; font-size: 0.875rem; cursor: pointer;
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.role-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
|
.role-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, watch, nextTick } from 'vue';
|
import { ref, reactive, computed, watch, nextTick } from 'vue';
|
||||||
import { settingsCategories } from './settingsConfig.js';
|
import { settingsGroups, settingsCategories } from './settingsConfig.js';
|
||||||
import SettingsField from './components/SettingsField.vue';
|
import SettingsField from './components/SettingsField.vue';
|
||||||
import { applyThemePalette, applyFontFamily } from './applyLiveTheme.js';
|
import { applyThemePalette, applyFontFamily } from './applyLiveTheme.js';
|
||||||
|
|
||||||
@@ -45,6 +45,29 @@ const activeCategory = computed(
|
|||||||
() => visibleCategories.find((c) => c.id === activeId.value) || visibleCategories[0]
|
() => visibleCategories.find((c) => c.id === activeId.value) || visibleCategories[0]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const groupOfCategory = (catId) =>
|
||||||
|
settingsGroups.find((g) => g.categories.some((c) => c.id === catId));
|
||||||
|
|
||||||
|
// Collapsible nav groups. Default open; collapse state persisted per group.
|
||||||
|
const OPEN_KEY = 'aurora-settings-groups-open';
|
||||||
|
const loadOpen = () => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(localStorage.getItem(OPEN_KEY)) || {};
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const openState = reactive(loadOpen());
|
||||||
|
// Keep the active category's group open so its item is always reachable.
|
||||||
|
const activeGroup = groupOfCategory(activeId.value);
|
||||||
|
if (activeGroup) openState[activeGroup.id] = true;
|
||||||
|
|
||||||
|
const isGroupOpen = (id) => openState[id] !== false;
|
||||||
|
const toggleGroup = (id) => {
|
||||||
|
openState[id] = !isGroupOpen(id);
|
||||||
|
localStorage.setItem(OPEN_KEY, JSON.stringify(openState));
|
||||||
|
};
|
||||||
|
|
||||||
// The content panel scrolls independently of the nav (see .settings__content
|
// The content panel scrolls independently of the nav (see .settings__content
|
||||||
// below) so picking a category from a scrolled-down spot in the nav doesn't
|
// below) so picking a category from a scrolled-down spot in the nav doesn't
|
||||||
// require scrolling the whole page back up to see it. But the panel is one
|
// require scrolling the whole page back up to see it. But the panel is one
|
||||||
@@ -56,6 +79,8 @@ const activeCategory = computed(
|
|||||||
const contentEl = ref(null);
|
const contentEl = ref(null);
|
||||||
const selectCategory = (id) => {
|
const selectCategory = (id) => {
|
||||||
activeId.value = id;
|
activeId.value = id;
|
||||||
|
const g = groupOfCategory(id);
|
||||||
|
if (g) openState[g.id] = true;
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
url.searchParams.set('category', id);
|
url.searchParams.set('category', id);
|
||||||
window.history.replaceState({}, '', url);
|
window.history.replaceState({}, '', url);
|
||||||
@@ -64,15 +89,25 @@ const selectCategory = (id) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Search filter over the nav.
|
// Search filter over the nav — matches on group title, category title, or
|
||||||
|
// subtitle; groups with no surviving categories drop out entirely.
|
||||||
const query = ref('');
|
const query = ref('');
|
||||||
const filteredCategories = computed(() => {
|
const searching = computed(() => query.value.trim().length > 0);
|
||||||
|
const filteredGroups = computed(() => {
|
||||||
const q = query.value.trim().toLowerCase();
|
const q = query.value.trim().toLowerCase();
|
||||||
if (!q) return visibleCategories;
|
if (!q) return settingsGroups;
|
||||||
return visibleCategories.filter(
|
return settingsGroups
|
||||||
|
.map((g) => {
|
||||||
|
const groupMatch = g.title.toLowerCase().includes(q);
|
||||||
|
const categories = g.categories.filter(
|
||||||
(c) =>
|
(c) =>
|
||||||
c.title.toLowerCase().includes(q) || c.subtitle.toLowerCase().includes(q)
|
groupMatch ||
|
||||||
|
c.title.toLowerCase().includes(q) ||
|
||||||
|
c.subtitle.toLowerCase().includes(q)
|
||||||
);
|
);
|
||||||
|
return { ...g, categories };
|
||||||
|
})
|
||||||
|
.filter((g) => g.categories.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Options for multiselect fields, resolved from server-provided lists.
|
// Options for multiselect fields, resolved from server-provided lists.
|
||||||
@@ -172,22 +207,39 @@ const importSettings = (e) => {
|
|||||||
<input v-model="query" type="text" placeholder="Search settings…" />
|
<input v-model="query" type="text" placeholder="Search settings…" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="settings__list">
|
<ul class="settings__groups">
|
||||||
<li v-for="cat in filteredCategories" :key="cat.id">
|
<li v-for="group in filteredGroups" :key="group.id" class="settings__group">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="settings__group-head"
|
||||||
|
:aria-expanded="isGroupOpen(group.id) || searching"
|
||||||
|
@click="toggleGroup(group.id)"
|
||||||
|
>
|
||||||
|
<span class="settings__group-icon dashicons" :class="group.icon" />
|
||||||
|
<span class="settings__group-title">{{ group.title }}</span>
|
||||||
|
<span
|
||||||
|
class="settings__group-caret dashicons dashicons-arrow-down-alt2"
|
||||||
|
:class="{ 'is-collapsed': !isGroupOpen(group.id) && !searching }"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<ul v-show="isGroupOpen(group.id) || searching" class="settings__list">
|
||||||
|
<li v-for="cat in group.categories" :key="cat.id">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="settings__cat"
|
class="settings__cat"
|
||||||
:class="{ 'settings__cat--active': cat.id === activeId }"
|
:class="{ 'settings__cat--active': cat.id === activeId }"
|
||||||
@click="selectCategory(cat.id)"
|
@click="selectCategory(cat.id)"
|
||||||
>
|
>
|
||||||
<span class="settings__cat-icon"><span class="dashicons" :class="cat.icon" /></span>
|
<span class="settings__cat-icon dashicons" :class="cat.icon" />
|
||||||
<span class="settings__cat-text">
|
|
||||||
<span class="settings__cat-title">{{ cat.title }}</span>
|
<span class="settings__cat-title">{{ cat.title }}</span>
|
||||||
<span class="settings__cat-sub">{{ cat.subtitle }}</span>
|
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li v-if="!filteredGroups.length" class="settings__empty">
|
||||||
|
No settings match “{{ query }}”.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Right content panel -->
|
<!-- Right content panel -->
|
||||||
@@ -250,7 +302,7 @@ const importSettings = (e) => {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: 16px;
|
border-radius: var(--aurora-radius-lg);
|
||||||
padding: 24px 20px;
|
padding: 24px 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -262,7 +314,7 @@ const importSettings = (e) => {
|
|||||||
.settings__actions { display: flex; gap: 4px; }
|
.settings__actions { display: flex; gap: 4px; }
|
||||||
.settings__actions button {
|
.settings__actions button {
|
||||||
width: 30px; height: 30px; border: none; background: none;
|
width: 30px; height: 30px; border: none; background: none;
|
||||||
color: var(--aurora-text-muted); cursor: pointer; border-radius: 7px;
|
color: var(--aurora-text-muted); cursor: pointer; border-radius: var(--aurora-radius-sm);
|
||||||
display: inline-flex; align-items: center; justify-content: center;
|
display: inline-flex; align-items: center; justify-content: center;
|
||||||
}
|
}
|
||||||
.settings__actions button:hover { background: var(--aurora-bg-subtle); color: var(--aurora-text); }
|
.settings__actions button:hover { background: var(--aurora-bg-subtle); color: var(--aurora-text); }
|
||||||
@@ -272,7 +324,7 @@ const importSettings = (e) => {
|
|||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 10px; padding: 8px 12px; margin-bottom: 16px;
|
border-radius: var(--aurora-radius-md); padding: 8px 12px; margin-bottom: 16px;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
}
|
}
|
||||||
.settings__search input {
|
.settings__search input {
|
||||||
@@ -280,27 +332,47 @@ const importSettings = (e) => {
|
|||||||
font-size: 0.8125rem; width: 100%;
|
font-size: 0.8125rem; width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings__list { list-style: none; margin: 0; padding: 0; }
|
.settings__groups { list-style: none; margin: 0; padding: 0; }
|
||||||
|
.settings__group { margin-bottom: 4px; }
|
||||||
|
|
||||||
|
.settings__group-head {
|
||||||
|
display: flex; align-items: center; gap: 8px; width: 100%;
|
||||||
|
padding: 6px 8px; border: none; background: none; cursor: pointer;
|
||||||
|
border-radius: var(--aurora-radius-sm); color: var(--aurora-text-muted);
|
||||||
|
}
|
||||||
|
.settings__group-head:hover { color: var(--aurora-text); }
|
||||||
|
.settings__group-icon { font-size: 15px; width: 16px; height: 16px; }
|
||||||
|
.settings__group-title {
|
||||||
|
font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.settings__group-caret {
|
||||||
|
margin-left: auto; font-size: 16px; width: 16px; height: 16px;
|
||||||
|
transition: transform 0.15s ease;
|
||||||
|
}
|
||||||
|
.settings__group-caret.is-collapsed { transform: rotate(-90deg); }
|
||||||
|
|
||||||
|
/* Indent the category items so they read as a submenu nested under their
|
||||||
|
group header, rather than sitting flush at the same level. */
|
||||||
|
.settings__list { list-style: none; margin: 2px 0 8px; padding: 0 0 0 14px; }
|
||||||
.settings__cat {
|
.settings__cat {
|
||||||
display: flex; align-items: center; gap: 12px; width: 100%;
|
display: flex; align-items: center; gap: 10px; width: 100%;
|
||||||
padding: 10px; border: none; background: none; cursor: pointer;
|
padding: 8px 10px; border: none; background: none; cursor: pointer;
|
||||||
border-radius: 12px; text-align: left; margin-bottom: 2px;
|
border-radius: var(--aurora-radius-md); text-align: left; margin-bottom: 1px;
|
||||||
|
color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.settings__cat:hover { background: var(--aurora-bg-subtle); }
|
.settings__cat:hover { background: var(--aurora-bg-subtle); }
|
||||||
.settings__cat--active { background: var(--aurora-accent-soft); }
|
.settings__cat--active { background: var(--aurora-accent-soft); }
|
||||||
.settings__cat-icon {
|
.settings__cat-icon {
|
||||||
width: 34px; height: 34px; flex-shrink: 0;
|
font-size: 16px; width: 18px; height: 18px; flex-shrink: 0;
|
||||||
border-radius: 9px; background: var(--aurora-bg-subtle);
|
|
||||||
display: flex; align-items: center; justify-content: center;
|
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
}
|
}
|
||||||
.settings__cat--active .settings__cat-icon { color: var(--aurora-accent); }
|
.settings__cat--active .settings__cat-icon { color: var(--aurora-accent); }
|
||||||
.settings__cat-text { display: flex; flex-direction: column; min-width: 0; }
|
.settings__cat-title { font-size: 0.8125rem; font-weight: 500; }
|
||||||
.settings__cat-title { font-size: 0.875rem; font-weight: 600; color: var(--aurora-text); }
|
.settings__cat--active .settings__cat-title { color: var(--aurora-accent); font-weight: 600; }
|
||||||
.settings__cat--active .settings__cat-title { color: var(--aurora-accent); }
|
|
||||||
.settings__cat-sub {
|
.settings__empty {
|
||||||
font-size: 0.75rem; color: var(--aurora-text-muted);
|
padding: 12px 10px; font-size: 0.8125rem; color: var(--aurora-text-muted);
|
||||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Right content — no background/border of its own, same reasoning.
|
/* Right content — no background/border of its own, same reasoning.
|
||||||
@@ -313,7 +385,7 @@ const importSettings = (e) => {
|
|||||||
flex: 1; min-width: 0;
|
flex: 1; min-width: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: 16px;
|
border-radius: var(--aurora-radius-lg);
|
||||||
padding: 28px 32px;
|
padding: 28px 32px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -330,7 +402,7 @@ const importSettings = (e) => {
|
|||||||
.settings__saved { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
.settings__saved { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
||||||
.settings__save {
|
.settings__save {
|
||||||
background: var(--aurora-accent); color: #fff; border: none;
|
background: var(--aurora-accent); color: #fff; border: none;
|
||||||
border-radius: 9px; padding: 9px 20px; font-size: 0.875rem; font-weight: 500; cursor: pointer;
|
border-radius: var(--aurora-radius-md); padding: 9px 20px; font-size: 0.875rem; font-weight: 500; cursor: pointer;
|
||||||
}
|
}
|
||||||
.settings__save:disabled { opacity: 0.6; cursor: default; }
|
.settings__save:disabled { opacity: 0.6; cursor: default; }
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ const installCompanion = async () => {
|
|||||||
<textarea
|
<textarea
|
||||||
v-else-if="field.type === 'textarea'"
|
v-else-if="field.type === 'textarea'"
|
||||||
class="field__input field__textarea"
|
class="field__input field__textarea"
|
||||||
|
:class="{ 'field__textarea--mono': field.mono }"
|
||||||
:placeholder="field.placeholder || ''"
|
:placeholder="field.placeholder || ''"
|
||||||
:rows="field.rows || 6"
|
:rows="field.rows || 6"
|
||||||
:value="val || ''"
|
:value="val || ''"
|
||||||
@@ -340,24 +341,29 @@ const installCompanion = async () => {
|
|||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
padding: 9px 12px;
|
padding: 9px 12px;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
.field__input:focus { outline: none; border-color: var(--aurora-accent); }
|
.field__input:focus { outline: none; border-color: var(--aurora-accent); }
|
||||||
.field__textarea { resize: vertical; font-family: inherit; line-height: 1.5; }
|
.field__textarea { resize: vertical; font-family: inherit; line-height: 1.5; }
|
||||||
|
.field__textarea--mono {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
tab-size: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.field__color { display: flex; align-items: center; gap: 10px; }
|
.field__color { display: flex; align-items: center; gap: 10px; }
|
||||||
.field__color input[type='color'] {
|
.field__color input[type='color'] {
|
||||||
width: 40px; height: 32px; border: 1px solid var(--aurora-border);
|
width: 40px; height: 32px; border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px; background: none; cursor: pointer; padding: 2px;
|
border-radius: var(--aurora-radius-sm); background: none; cursor: pointer; padding: 2px;
|
||||||
}
|
}
|
||||||
.field__color-hex { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
.field__color-hex { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
||||||
|
|
||||||
.field__image {
|
.field__image {
|
||||||
width: 160px; height: 120px;
|
width: 160px; height: 120px;
|
||||||
border: 1px dashed var(--aurora-border);
|
border: 1px dashed var(--aurora-border);
|
||||||
border-radius: 12px;
|
border-radius: var(--aurora-radius-md);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||||
gap: 8px; cursor: pointer; color: var(--aurora-text-muted);
|
gap: 8px; cursor: pointer; color: var(--aurora-text-muted);
|
||||||
@@ -376,13 +382,13 @@ const installCompanion = async () => {
|
|||||||
.field__repeater-remove {
|
.field__repeater-remove {
|
||||||
flex-shrink: 0; width: 34px; border: 1px solid var(--aurora-border);
|
flex-shrink: 0; width: 34px; border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle); color: var(--aurora-text-muted);
|
background: var(--aurora-bg-subtle); color: var(--aurora-text-muted);
|
||||||
border-radius: 8px; cursor: pointer; font-size: 1.1rem;
|
border-radius: var(--aurora-radius-sm); cursor: pointer; font-size: 1.1rem;
|
||||||
}
|
}
|
||||||
.field__newitem {
|
.field__newitem {
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
border-radius: 8px; padding: 8px 16px; font-size: 0.8125rem; cursor: pointer;
|
border-radius: var(--aurora-radius-sm); padding: 8px 16px; font-size: 0.8125rem; cursor: pointer;
|
||||||
}
|
}
|
||||||
.field__newitem:hover { border-color: var(--aurora-accent); color: var(--aurora-accent); }
|
.field__newitem:hover { border-color: var(--aurora-accent); color: var(--aurora-accent); }
|
||||||
|
|
||||||
@@ -400,13 +406,13 @@ const installCompanion = async () => {
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 9px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
}
|
}
|
||||||
.field__seg button {
|
.field__seg button {
|
||||||
border: none; background: none; cursor: pointer;
|
border: none; background: none; cursor: pointer;
|
||||||
padding: 6px 26px; border-radius: 7px;
|
padding: 6px 26px; border-radius: var(--aurora-radius-sm);
|
||||||
font-size: 0.8125rem; color: var(--aurora-text-muted);
|
font-size: 0.8125rem; color: var(--aurora-text-muted);
|
||||||
}
|
}
|
||||||
.field__seg--active { background: var(--aurora-accent); color: #fff !important; }
|
.field__seg--active { background: var(--aurora-accent); color: #fff !important; }
|
||||||
@@ -417,13 +423,13 @@ const installCompanion = async () => {
|
|||||||
display: flex; flex-direction: column; align-items: center; gap: 6px;
|
display: flex; flex-direction: column; align-items: center; gap: 6px;
|
||||||
width: 76px; padding: 10px 6px;
|
width: 76px; padding: 10px 6px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.field__theme-card--active { border-color: var(--aurora-accent); box-shadow: 0 0 0 1px var(--aurora-accent); }
|
.field__theme-card--active { border-color: var(--aurora-accent); box-shadow: 0 0 0 1px var(--aurora-accent); }
|
||||||
.field__theme-swatch {
|
.field__theme-swatch {
|
||||||
width: 36px; height: 36px; border-radius: 10px;
|
width: 36px; height: 36px; border-radius: var(--aurora-radius-md);
|
||||||
border: 1px solid var(--aurora-card-border);
|
border: 1px solid var(--aurora-card-border);
|
||||||
display: flex; align-items: flex-end; justify-content: flex-end;
|
display: flex; align-items: flex-end; justify-content: flex-end;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
@@ -441,14 +447,14 @@ const installCompanion = async () => {
|
|||||||
max-height: 260px; overflow-y: auto; z-index: 20;
|
max-height: 260px; overflow-y: auto; z-index: 20;
|
||||||
background: var(--aurora-card-bg);
|
background: var(--aurora-card-bg);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
.field__font-item {
|
.field__font-item {
|
||||||
display: block; width: 100%; text-align: left;
|
display: block; width: 100%; text-align: left;
|
||||||
border: none; background: none; cursor: pointer;
|
border: none; background: none; cursor: pointer;
|
||||||
padding: 8px 10px; border-radius: 7px;
|
padding: 8px 10px; border-radius: var(--aurora-radius-sm);
|
||||||
font-size: 0.875rem; color: var(--aurora-text);
|
font-size: 0.875rem; color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.field__font-item:hover { background: var(--aurora-bg-subtle); }
|
.field__font-item:hover { background: var(--aurora-bg-subtle); }
|
||||||
@@ -457,7 +463,7 @@ const installCompanion = async () => {
|
|||||||
/* Companion plugin install card */
|
/* Companion plugin install card */
|
||||||
.field__companion-status { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
.field__companion-status { font-size: 0.8125rem; color: var(--aurora-text-muted); }
|
||||||
.field__companion-install {
|
.field__companion-install {
|
||||||
border: none; border-radius: 8px; background: var(--aurora-accent); color: #fff;
|
border: none; border-radius: var(--aurora-radius-sm); background: var(--aurora-accent); color: #fff;
|
||||||
padding: 8px 16px; font-size: 0.8125rem; font-weight: 600; cursor: pointer;
|
padding: 8px 16px; font-size: 0.8125rem; font-weight: 600; cursor: pointer;
|
||||||
}
|
}
|
||||||
.field__companion-install:disabled { opacity: 0.6; cursor: default; }
|
.field__companion-install:disabled { opacity: 0.6; cursor: default; }
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
* Declarative settings schema for the Aurora Admin settings page.
|
* Declarative settings schema for the Aurora Admin settings page.
|
||||||
* Each category renders as an item in the left nav; its fields render in
|
*
|
||||||
* the right panel. Field `key`s map directly into the aurora_admin_settings
|
* Categories are organized into top-level groups. Each group renders as a
|
||||||
* option, saved via the wp/v2/settings REST route.
|
* collapsible section in the left nav; each category within it renders as a
|
||||||
|
* nav item, and its fields render in the right panel. Field `key`s map
|
||||||
|
* directly into the aurora_admin_settings option, saved via the
|
||||||
|
* wp/v2/settings REST route.
|
||||||
*/
|
*/
|
||||||
export const settingsCategories = [
|
export const settingsGroups = [
|
||||||
|
{
|
||||||
|
id: 'general',
|
||||||
|
title: 'General',
|
||||||
|
icon: 'dashicons-admin-settings',
|
||||||
|
categories: [
|
||||||
{
|
{
|
||||||
id: 'general',
|
id: 'general',
|
||||||
title: 'General',
|
title: 'General',
|
||||||
@@ -47,25 +55,33 @@ export const settingsCategories = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'login',
|
id: 'analytics',
|
||||||
title: 'Login',
|
title: 'Analytics',
|
||||||
subtitle: 'Customize login page appearance and security',
|
subtitle: 'Built-in analytics and tracking settings',
|
||||||
icon: 'dashicons-lock',
|
icon: 'dashicons-chart-bar',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
key: 'style_login',
|
key: 'enable_analytics',
|
||||||
type: 'toggle',
|
type: 'toggle',
|
||||||
label: 'Style login page',
|
label: 'Enable analytics',
|
||||||
description: 'Apply the Aurora theme to the WordPress login screen.',
|
description: 'Track first-party visitor analytics for the dashboard.',
|
||||||
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'login_logo',
|
key: 'track_admins',
|
||||||
type: 'image',
|
type: 'toggle',
|
||||||
label: 'Login logo',
|
label: 'Track logged-in admins',
|
||||||
description: 'Replace the WordPress logo on the login screen.',
|
description: 'Include administrator visits in analytics (off by default).',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'appearance',
|
||||||
|
title: 'Appearance',
|
||||||
|
icon: 'dashicons-admin-appearance',
|
||||||
|
categories: [
|
||||||
{
|
{
|
||||||
id: 'theme',
|
id: 'theme',
|
||||||
title: 'Theme',
|
title: 'Theme',
|
||||||
@@ -104,7 +120,7 @@ export const settingsCategories = [
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
label: 'Rename Aurora Admin',
|
label: 'Rename Aurora Admin',
|
||||||
description:
|
description:
|
||||||
"This will rename Aurora Admin in the plugins list as well as renaming its settings link.",
|
'This will rename Aurora Admin in the plugins list as well as renaming its settings link.',
|
||||||
placeholder: 'Aurora Admin',
|
placeholder: 'Aurora Admin',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -117,6 +133,68 @@ export const settingsCategories = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'login',
|
||||||
|
title: 'Login',
|
||||||
|
subtitle: 'Customize login page appearance and security',
|
||||||
|
icon: 'dashicons-lock',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'style_login',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Style login page',
|
||||||
|
description: 'Apply the Aurora theme to the WordPress login screen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'login_logo',
|
||||||
|
type: 'image',
|
||||||
|
label: 'Login logo',
|
||||||
|
description: 'Replace the WordPress logo on the login screen.',
|
||||||
|
dependsOn: 'style_login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'login_bg_image',
|
||||||
|
type: 'image',
|
||||||
|
label: 'Background image',
|
||||||
|
description: 'Full-screen background for the login page. Overrides the background color below.',
|
||||||
|
dependsOn: 'style_login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'login_bg_color',
|
||||||
|
type: 'color',
|
||||||
|
label: 'Background color',
|
||||||
|
description: 'Solid background color for the login page (used when no background image is set).',
|
||||||
|
default: '#0f1420',
|
||||||
|
dependsOn: 'style_login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'login_form_bg',
|
||||||
|
type: 'color',
|
||||||
|
label: 'Form background',
|
||||||
|
description: 'Background color of the login form panel.',
|
||||||
|
default: '#1c2333',
|
||||||
|
dependsOn: 'style_login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'login_button_color',
|
||||||
|
type: 'color',
|
||||||
|
label: 'Button color',
|
||||||
|
description: 'Color of the primary “Log In” button and the field focus accent.',
|
||||||
|
default: '#4f7cff',
|
||||||
|
dependsOn: 'style_login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'login_custom_css',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 8,
|
||||||
|
label: 'Custom login CSS',
|
||||||
|
description: 'Extra CSS applied to the login screen, after Aurora’s own styles.',
|
||||||
|
placeholder: 'body.login { … }',
|
||||||
|
dependsOn: 'style_login',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'menu',
|
id: 'menu',
|
||||||
title: 'Menu',
|
title: 'Menu',
|
||||||
@@ -131,51 +209,13 @@ export const settingsCategories = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'posts',
|
|
||||||
title: 'Posts',
|
|
||||||
subtitle: 'Post management and display preferences',
|
|
||||||
icon: 'dashicons-admin-post',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'modern_posts',
|
|
||||||
type: 'toggle',
|
|
||||||
label: 'Modern posts table',
|
|
||||||
description: 'Use the Aurora posts management interface.',
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'pages',
|
id: 'screens',
|
||||||
title: 'Pages',
|
title: 'Screens',
|
||||||
subtitle: 'Page management and display preferences',
|
icon: 'dashicons-desktop',
|
||||||
icon: 'dashicons-admin-page',
|
categories: [
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'modern_pages',
|
|
||||||
type: 'toggle',
|
|
||||||
label: 'Modern pages table',
|
|
||||||
description: 'Use the Aurora pages management interface.',
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'plugins',
|
|
||||||
title: 'Plugins',
|
|
||||||
subtitle: 'Plugin management interface options',
|
|
||||||
icon: 'dashicons-admin-plugins',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'modern_plugins',
|
|
||||||
type: 'toggle',
|
|
||||||
label: 'Modern plugins page',
|
|
||||||
description: 'Use the Aurora plugins management interface.',
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'dashboard',
|
id: 'dashboard',
|
||||||
title: 'Dashboard',
|
title: 'Dashboard',
|
||||||
@@ -192,77 +232,78 @@ export const settingsCategories = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'analytics',
|
id: 'content-tables',
|
||||||
title: 'Analytics',
|
title: 'Content tables',
|
||||||
subtitle: 'Built-in analytics and tracking settings',
|
subtitle: 'Choose which admin list screens use the Aurora interface',
|
||||||
icon: 'dashicons-chart-bar',
|
icon: 'dashicons-editor-table',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
key: 'enable_analytics',
|
key: 'modern_posts',
|
||||||
type: 'toggle',
|
type: 'toggle',
|
||||||
label: 'Enable analytics',
|
label: 'Posts',
|
||||||
description: 'Track first-party visitor analytics for the dashboard.',
|
description: 'Use the Aurora posts management interface.',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'track_admins',
|
key: 'modern_pages',
|
||||||
type: 'toggle',
|
type: 'toggle',
|
||||||
label: 'Track logged-in admins',
|
label: 'Pages',
|
||||||
description: 'Include administrator visits in analytics (off by default).',
|
description: 'Use the Aurora pages management interface.',
|
||||||
|
default: true,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'media',
|
|
||||||
title: 'Media',
|
|
||||||
subtitle: 'Media library and upload management settings',
|
|
||||||
icon: 'dashicons-admin-media',
|
|
||||||
fields: [
|
|
||||||
{
|
{
|
||||||
key: 'modern_media',
|
key: 'modern_media',
|
||||||
type: 'toggle',
|
type: 'toggle',
|
||||||
label: 'Modern media library',
|
label: 'Media library',
|
||||||
description: 'Use the Aurora media library interface.',
|
description: 'Use the Aurora media library interface.',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'enable_svg',
|
|
||||||
type: 'toggle',
|
|
||||||
label: 'Allow SVG uploads',
|
|
||||||
description: 'Permit SVG files to be uploaded to the media library.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'users',
|
|
||||||
title: 'Users',
|
|
||||||
subtitle: 'User management and administration settings',
|
|
||||||
icon: 'dashicons-admin-users',
|
|
||||||
fields: [
|
|
||||||
{
|
{
|
||||||
key: 'modern_users',
|
key: 'modern_users',
|
||||||
type: 'toggle',
|
type: 'toggle',
|
||||||
label: 'Modern users page',
|
label: 'Users',
|
||||||
description: 'Use the Aurora users management interface.',
|
description: 'Use the Aurora users management interface.',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'comments',
|
|
||||||
title: 'Comments',
|
|
||||||
subtitle: 'Comment management and administration',
|
|
||||||
icon: 'dashicons-admin-comments',
|
|
||||||
fields: [
|
|
||||||
{
|
{
|
||||||
key: 'modern_comments',
|
key: 'modern_comments',
|
||||||
type: 'toggle',
|
type: 'toggle',
|
||||||
label: 'Modern comments page',
|
label: 'Comments',
|
||||||
description: 'Use the Aurora comments management interface.',
|
description: 'Use the Aurora comments management interface.',
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'modern_plugins',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Plugins',
|
||||||
|
description: 'Use the Aurora plugins management interface.',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'admin-takeover',
|
||||||
|
title: 'Admin Takeover',
|
||||||
|
subtitle: 'Replace the remaining native WordPress admin screens with Aurora',
|
||||||
|
icon: 'dashicons-shield',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'full_admin_takeover',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Full admin takeover',
|
||||||
|
description:
|
||||||
|
'Replace Media Upload, Add User, Profile, Appearance, Tools, and native Settings screens with Aurora equivalents. Off by default — these cover more ground than Posts/Pages/Media/Users/Comments, so it’s opt-in rather than on by default.',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'productivity',
|
||||||
|
title: 'Productivity',
|
||||||
|
icon: 'dashicons-superhero-alt',
|
||||||
|
categories: [
|
||||||
{
|
{
|
||||||
id: 'image-formats',
|
id: 'image-formats',
|
||||||
title: 'Modern Image Formats',
|
title: 'Modern Image Formats',
|
||||||
@@ -302,6 +343,161 @@ export const settingsCategories = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'media',
|
||||||
|
title: 'Media',
|
||||||
|
subtitle: 'Media library and upload options',
|
||||||
|
icon: 'dashicons-admin-media',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'enable_svg',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Allow SVG uploads',
|
||||||
|
description: 'Permit SVG files to be uploaded to the media library.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'security',
|
||||||
|
title: 'Security & performance',
|
||||||
|
icon: 'dashicons-shield',
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
id: 'security-hardening',
|
||||||
|
title: 'Hardening',
|
||||||
|
subtitle: 'Reduce your site’s attack surface and trim unnecessary output',
|
||||||
|
icon: 'dashicons-shield-alt',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'disable_xmlrpc',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Disable XML-RPC',
|
||||||
|
description:
|
||||||
|
'Turn off the XML-RPC endpoint, a common brute-force and pingback-DDoS vector. Leave on only if you rely on the WordPress mobile app or remote publishing.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'disable_comments',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Disable comments',
|
||||||
|
description:
|
||||||
|
'Turn comments off site-wide — closes them on every post type, hides existing ones, and removes the Comments admin screen and dashboard widget.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'remove_head_junk',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Clean up <head>',
|
||||||
|
description:
|
||||||
|
'Remove the WordPress generator/version tag, RSD link, WLW manifest, and shortlink meta from your site’s <head>.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'performance-tweaks',
|
||||||
|
title: 'Performance',
|
||||||
|
subtitle: 'Trim requests and scripts WordPress loads by default',
|
||||||
|
icon: 'dashicons-performance',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'disable_emojis',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Disable emoji scripts',
|
||||||
|
description:
|
||||||
|
'Stop WordPress loading its emoji-detection script and styles on every front-end and admin page.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'disable_oembed',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Disable oEmbeds',
|
||||||
|
description:
|
||||||
|
'Remove oEmbed discovery links and the wp-embed script (stops auto-embedding of pasted URLs and the embed REST route).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'heartbeat_mode',
|
||||||
|
type: 'select',
|
||||||
|
label: 'Heartbeat API',
|
||||||
|
description:
|
||||||
|
'The Heartbeat API polls the server on a timer (autosave, post-lock notices). Slow it down or disable it to cut admin-ajax load.',
|
||||||
|
default: 'default',
|
||||||
|
options: [
|
||||||
|
{ value: 'default', label: 'Default (15–60s)' },
|
||||||
|
{ value: 'slow', label: 'Slow (60s)' },
|
||||||
|
{ value: 'disabled', label: 'Disabled' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'code',
|
||||||
|
title: 'Code',
|
||||||
|
icon: 'dashicons-editor-code',
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
id: 'custom-code',
|
||||||
|
title: 'Custom CSS & JS',
|
||||||
|
subtitle: 'Inject your own CSS and JavaScript into the WordPress admin',
|
||||||
|
icon: 'dashicons-admin-customizer',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'custom_admin_css',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 10,
|
||||||
|
label: 'Admin CSS',
|
||||||
|
description:
|
||||||
|
'CSS added to every wp-admin page, inside a <style> tag in the admin <head>. Enter CSS only — no <style> tags needed.',
|
||||||
|
placeholder: '.wrap { max-width: 1200px; }',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'custom_admin_js',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 10,
|
||||||
|
label: 'Admin JavaScript',
|
||||||
|
description:
|
||||||
|
'JavaScript added to the admin footer, inside a <script> tag. Enter JS only — no <script> tags needed.',
|
||||||
|
placeholder: "console.log('Hello from Aurora');",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'header-footer',
|
||||||
|
title: 'Header & footer scripts',
|
||||||
|
subtitle: 'Inject raw code into your site’s front-end <head> and footer',
|
||||||
|
icon: 'dashicons-editor-code',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'header_scripts',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 8,
|
||||||
|
label: 'Header scripts',
|
||||||
|
description:
|
||||||
|
'Raw HTML/JS printed in the front-end <head> — analytics snippets, verification meta tags, etc. Include the full <script>/<meta> tags.',
|
||||||
|
placeholder: '<!-- e.g. analytics -->\n<script>…</script>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'footer_scripts',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 8,
|
||||||
|
label: 'Footer scripts',
|
||||||
|
description:
|
||||||
|
'Raw HTML/JS printed just before </body> on the front end. Include the full <script> tags.',
|
||||||
|
placeholder: '<script>…</script>',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'add-ons',
|
||||||
|
title: 'Add-ons',
|
||||||
|
icon: 'dashicons-admin-plugins',
|
||||||
|
categories: [
|
||||||
{
|
{
|
||||||
id: 'add-ons',
|
id: 'add-ons',
|
||||||
title: 'Add-ons',
|
title: 'Add-ons',
|
||||||
@@ -340,20 +536,12 @@ export const settingsCategories = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'admin-takeover',
|
|
||||||
title: 'Admin Takeover',
|
|
||||||
subtitle: 'Replace the remaining native WordPress admin screens with Aurora',
|
|
||||||
icon: 'dashicons-shield',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'full_admin_takeover',
|
|
||||||
type: 'toggle',
|
|
||||||
label: 'Full admin takeover',
|
|
||||||
description:
|
|
||||||
'Replace Media Upload, Add User, Profile, Appearance, Tools, and native Settings screens with Aurora equivalents. Off by default — these cover more ground than Posts/Pages/Media/Users/Comments, so it’s opt-in rather than on by default.',
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flattened category list — every category across all groups, in order.
|
||||||
|
* Used for default-seeding, active-category lookup, and URL deep-links.
|
||||||
|
*/
|
||||||
|
export const settingsCategories = settingsGroups.flatMap((g) => g.categories);
|
||||||
|
|||||||
@@ -0,0 +1,310 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, reactive, computed, watch, onMounted } from 'vue';
|
||||||
|
import SettingsField from '@/pages/settings/components/SettingsField.vue';
|
||||||
|
import { applyThemePalette, applyFontFamily } from '@/pages/settings/applyLiveTheme.js';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
serverData: { type: Object, required: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step definitions. Welcome and Done are custom content; the middle three
|
||||||
|
// render their `fields` through the shared SettingsField component (same
|
||||||
|
// controls as the settings page — theme picker, font picker, media-library
|
||||||
|
// image fields, toggles).
|
||||||
|
const steps = [
|
||||||
|
{ id: 'welcome', label: 'Welcome' },
|
||||||
|
{
|
||||||
|
id: 'appearance',
|
||||||
|
label: 'Appearance',
|
||||||
|
title: 'Choose your look',
|
||||||
|
subtitle:
|
||||||
|
'Pick a color theme and font for the whole admin. You can change these any time in Settings.',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'theme_preset',
|
||||||
|
type: 'theme-picker',
|
||||||
|
label: 'Theme',
|
||||||
|
description: 'The accent and surface colors used across the admin.',
|
||||||
|
default: 'indigo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'font_family',
|
||||||
|
type: 'font-picker',
|
||||||
|
label: 'Font family',
|
||||||
|
description: 'A Google Font used across the Aurora interface.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'branding',
|
||||||
|
label: 'Branding',
|
||||||
|
title: 'Add your branding',
|
||||||
|
subtitle:
|
||||||
|
'All optional — drop in a logo and favicon, or rename Aurora for a fully white-labeled admin.',
|
||||||
|
fields: [
|
||||||
|
{ key: 'logo', type: 'image', label: 'Logo', description: 'Shown at the top of the sidebar menu.' },
|
||||||
|
{
|
||||||
|
key: 'dark_logo',
|
||||||
|
type: 'image',
|
||||||
|
label: 'Dark mode logo',
|
||||||
|
description: 'Optional alternative logo; falls back to the standard one.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'admin_favicon',
|
||||||
|
type: 'image',
|
||||||
|
label: 'Admin favicon',
|
||||||
|
description: 'Replaces the WordPress favicon in the admin.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'plugin_name',
|
||||||
|
type: 'text',
|
||||||
|
label: 'Rename Aurora Admin',
|
||||||
|
description: 'White-labels the plugin name in menus and the plugins list.',
|
||||||
|
placeholder: 'Aurora Admin',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'features',
|
||||||
|
label: 'Features',
|
||||||
|
title: 'Choose your features',
|
||||||
|
subtitle:
|
||||||
|
'Aurora replaces these WordPress admin screens with faster versions of its own. Turn off any you’d rather keep native.',
|
||||||
|
fields: [
|
||||||
|
{ key: 'use_custom_dashboard', type: 'toggle', label: 'Dashboard', description: 'Replace the WordPress dashboard with Aurora’s.', default: true },
|
||||||
|
{ key: 'modern_posts', type: 'toggle', label: 'Posts', description: 'Aurora posts management screen.', default: true },
|
||||||
|
{ key: 'modern_pages', type: 'toggle', label: 'Pages', description: 'Aurora pages management screen.', default: true },
|
||||||
|
{ key: 'modern_media', type: 'toggle', label: 'Media library', description: 'Aurora media library screen.', default: true },
|
||||||
|
{ key: 'modern_users', type: 'toggle', label: 'Users', description: 'Aurora users management screen.', default: true },
|
||||||
|
{ key: 'modern_comments', type: 'toggle', label: 'Comments', description: 'Aurora comments management screen.', default: true },
|
||||||
|
{ key: 'modern_plugins', type: 'toggle', label: 'Plugins', description: 'Aurora plugins management screen.', default: true },
|
||||||
|
{
|
||||||
|
key: 'full_admin_takeover',
|
||||||
|
type: 'toggle',
|
||||||
|
label: 'Full admin takeover',
|
||||||
|
description: 'Also replace Appearance, Tools, and the native Settings screens. Off by default.',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ id: 'done', label: 'Done', title: 'You’re all set' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Working settings, seeded from the server + each field's default.
|
||||||
|
const settings = reactive({ ...(props.serverData.settings || {}) });
|
||||||
|
steps.forEach((s) =>
|
||||||
|
(s.fields || []).forEach((f) => {
|
||||||
|
if (settings[f.key] === undefined && f.default !== undefined) settings[f.key] = f.default;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const stepIndex = ref(0);
|
||||||
|
const current = computed(() => steps[stepIndex.value]);
|
||||||
|
const isFirst = computed(() => stepIndex.value === 0);
|
||||||
|
const isDone = computed(() => current.value.id === 'done');
|
||||||
|
|
||||||
|
const goNext = () => {
|
||||||
|
if (stepIndex.value < steps.length - 1) stepIndex.value++;
|
||||||
|
};
|
||||||
|
const goBack = () => {
|
||||||
|
if (stepIndex.value > 0) stepIndex.value--;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Live preview of theme + font as they're picked (nothing is persisted until
|
||||||
|
// the wizard is finished, but the whole admin previews immediately).
|
||||||
|
watch(() => settings.theme_preset, (p) => applyThemePalette(p || 'indigo'), { immediate: true });
|
||||||
|
watch(() => settings.font_family, (f) => applyFontFamily(f), { immediate: true });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// The shell (which normally does this) is disabled on this page.
|
||||||
|
document.documentElement.classList.add('aurora-dark');
|
||||||
|
applyThemePalette(settings.theme_preset || 'indigo');
|
||||||
|
applyFontFamily(settings.font_family);
|
||||||
|
});
|
||||||
|
|
||||||
|
const saving = ref(false);
|
||||||
|
const finish = async (target) => {
|
||||||
|
if (saving.value) return;
|
||||||
|
saving.value = true;
|
||||||
|
try {
|
||||||
|
await fetch(`${props.serverData.restUrl}wp/v2/settings`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': props.serverData.restNonce },
|
||||||
|
body: JSON.stringify({ aurora_admin_settings: { ...settings } }),
|
||||||
|
});
|
||||||
|
await fetch(`${props.serverData.restUrl}aurora-admin/v1/setup/complete`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': props.serverData.restNonce },
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
/* Even if persistence fails, don't trap the user in the wizard. */
|
||||||
|
}
|
||||||
|
window.location.href = target || props.serverData.dashboardUrl || '/wp-admin/';
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="wiz">
|
||||||
|
<div class="wiz__inner">
|
||||||
|
<div class="wiz__brand">
|
||||||
|
<span class="wiz__mark">A</span>
|
||||||
|
<span class="wiz__brandname">Aurora Admin</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Progress -->
|
||||||
|
<ol class="wiz__steps">
|
||||||
|
<template v-for="(s, i) in steps" :key="s.id">
|
||||||
|
<li
|
||||||
|
class="wiz__step"
|
||||||
|
:class="{ 'is-active': i === stepIndex, 'is-done': i < stepIndex }"
|
||||||
|
>
|
||||||
|
<span class="wiz__dot">
|
||||||
|
<span v-if="i < stepIndex" class="dashicons dashicons-yes" />
|
||||||
|
<span v-else>{{ i + 1 }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="wiz__step-label">{{ s.label }}</span>
|
||||||
|
</li>
|
||||||
|
<li v-if="i < steps.length - 1" class="wiz__connector" :class="{ 'is-on': i < stepIndex }" />
|
||||||
|
</template>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<!-- Card -->
|
||||||
|
<section class="wiz__card">
|
||||||
|
<!-- Welcome -->
|
||||||
|
<div v-if="current.id === 'welcome'" class="wiz__welcome">
|
||||||
|
<h1 class="wiz__h1">Welcome to Aurora Admin<span v-if="serverData.userName">, {{ serverData.userName }}</span></h1>
|
||||||
|
<p class="wiz__lead">
|
||||||
|
A modern, fast redesign of the WordPress admin. This quick setup takes about a
|
||||||
|
minute — choose a look, add your branding, and pick which screens Aurora takes over.
|
||||||
|
You can skip it and change everything later in Settings.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Done -->
|
||||||
|
<div v-else-if="current.id === 'done'" class="wiz__welcome">
|
||||||
|
<span class="wiz__done-icon dashicons dashicons-yes-alt" />
|
||||||
|
<h1 class="wiz__h1">You’re all set</h1>
|
||||||
|
<p class="wiz__lead">
|
||||||
|
Aurora is configured and ready. Head to your dashboard, or fine-tune anything in
|
||||||
|
Settings.
|
||||||
|
</p>
|
||||||
|
<div class="wiz__done-actions">
|
||||||
|
<button type="button" class="wiz__btn wiz__btn--primary" :disabled="saving" @click="finish(serverData.dashboardUrl)">
|
||||||
|
{{ saving ? 'Finishing…' : 'Go to dashboard' }}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="wiz__btn" :disabled="saving" @click="finish(serverData.settingsUrl)">
|
||||||
|
Open settings
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Field steps -->
|
||||||
|
<div v-else>
|
||||||
|
<h1 class="wiz__h1">{{ current.title }}</h1>
|
||||||
|
<p v-if="current.subtitle" class="wiz__lead">{{ current.subtitle }}</p>
|
||||||
|
<div class="wiz__fields">
|
||||||
|
<SettingsField
|
||||||
|
v-for="f in current.fields"
|
||||||
|
:key="f.key"
|
||||||
|
:field="f"
|
||||||
|
:api="null"
|
||||||
|
v-model="settings[f.key]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Footer nav (hidden on the Done step, which has its own actions) -->
|
||||||
|
<div v-if="!isDone" class="wiz__nav">
|
||||||
|
<button type="button" class="wiz__btn wiz__btn--ghost" :disabled="saving" @click="finish(serverData.dashboardUrl)">
|
||||||
|
Skip setup
|
||||||
|
</button>
|
||||||
|
<div class="wiz__nav-right">
|
||||||
|
<button v-if="!isFirst" type="button" class="wiz__btn" @click="goBack">Back</button>
|
||||||
|
<button type="button" class="wiz__btn wiz__btn--primary" @click="goNext">
|
||||||
|
{{ isFirst ? 'Get started' : 'Continue' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.wiz {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 100000;
|
||||||
|
overflow-y: auto;
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--aurora-accent) 12%, var(--aurora-app-bg-solid)) 0%, var(--aurora-app-bg-solid) 65%);
|
||||||
|
color: var(--aurora-text);
|
||||||
|
font-family: var(--aurora-font-family);
|
||||||
|
}
|
||||||
|
.wiz__inner {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 48px 24px 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiz__brand { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 30px; }
|
||||||
|
.wiz__mark {
|
||||||
|
width: 30px; height: 30px; border-radius: var(--aurora-radius-md);
|
||||||
|
background: var(--aurora-accent); color: #fff;
|
||||||
|
display: flex; align-items: center; justify-content: center; font-weight: 700;
|
||||||
|
}
|
||||||
|
.wiz__brandname { font-size: 1rem; font-weight: 500; }
|
||||||
|
|
||||||
|
/* Progress */
|
||||||
|
.wiz__steps { display: flex; align-items: center; justify-content: center; list-style: none; margin: 0 0 30px; padding: 0; }
|
||||||
|
.wiz__step { display: flex; flex-direction: column; align-items: center; gap: 7px; flex: 0 0 auto; }
|
||||||
|
.wiz__dot {
|
||||||
|
width: 28px; height: 28px; border-radius: 50%;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 0.75rem; font-weight: 500;
|
||||||
|
border: 1.5px solid var(--aurora-border); background: var(--aurora-card-bg); color: var(--aurora-text-muted);
|
||||||
|
}
|
||||||
|
.wiz__dot .dashicons { font-size: 16px; width: 16px; height: 16px; }
|
||||||
|
.wiz__step.is-done .wiz__dot { background: var(--aurora-accent); border-color: var(--aurora-accent); color: #fff; }
|
||||||
|
.wiz__step.is-active .wiz__dot { border-color: var(--aurora-accent); color: var(--aurora-accent); }
|
||||||
|
.wiz__step-label { font-size: 0.6875rem; color: var(--aurora-text-muted); }
|
||||||
|
.wiz__step.is-active .wiz__step-label, .wiz__step.is-done .wiz__step-label { color: var(--aurora-text); }
|
||||||
|
.wiz__connector { flex: 1 1 auto; height: 1.5px; min-width: 22px; background: var(--aurora-border); margin: 0 6px; position: relative; top: -10px; }
|
||||||
|
.wiz__connector.is-on { background: var(--aurora-accent); }
|
||||||
|
|
||||||
|
/* Card */
|
||||||
|
.wiz__card {
|
||||||
|
background: var(--aurora-card-bg);
|
||||||
|
border: 1px solid var(--aurora-border);
|
||||||
|
border-radius: var(--aurora-radius-xl);
|
||||||
|
padding: 30px 32px;
|
||||||
|
}
|
||||||
|
.wiz__h1 { font-size: 1.5rem; font-weight: 600; margin: 0; }
|
||||||
|
.wiz__lead { margin: 10px 0 0; font-size: 0.9rem; color: var(--aurora-text-muted); line-height: 1.6; }
|
||||||
|
|
||||||
|
.wiz__welcome { text-align: center; padding: 20px 8px; }
|
||||||
|
.wiz__welcome .wiz__lead { max-width: 520px; margin: 12px auto 0; }
|
||||||
|
.wiz__done-icon { font-size: 52px; width: 52px; height: 52px; color: var(--aurora-accent); }
|
||||||
|
.wiz__done-actions { display: flex; gap: 12px; justify-content: center; margin-top: 26px; }
|
||||||
|
|
||||||
|
/* Fields: SettingsField renders its own rows; drop the first row's top pad
|
||||||
|
and the last row's divider so they sit cleanly inside the card. */
|
||||||
|
.wiz__fields { margin-top: 8px; }
|
||||||
|
.wiz__fields > :deep(.field):first-child { padding-top: 12px; }
|
||||||
|
.wiz__fields > :deep(.field):last-child { border-bottom: none; padding-bottom: 4px; }
|
||||||
|
|
||||||
|
/* Nav */
|
||||||
|
.wiz__nav { display: flex; align-items: center; justify-content: space-between; margin-top: 22px; }
|
||||||
|
.wiz__nav-right { display: flex; gap: 10px; }
|
||||||
|
.wiz__btn {
|
||||||
|
font-size: 0.875rem; font-weight: 500;
|
||||||
|
padding: 10px 20px; border-radius: var(--aurora-radius-md); cursor: pointer;
|
||||||
|
border: 1px solid var(--aurora-border); background: var(--aurora-card-bg); color: var(--aurora-text);
|
||||||
|
}
|
||||||
|
.wiz__btn:hover { border-color: var(--aurora-accent); }
|
||||||
|
.wiz__btn:disabled { opacity: 0.6; cursor: default; }
|
||||||
|
.wiz__btn--ghost { border-color: transparent; color: var(--aurora-text-muted); }
|
||||||
|
.wiz__btn--ghost:hover { color: var(--aurora-text); border-color: transparent; }
|
||||||
|
.wiz__btn--primary { background: var(--aurora-accent); color: #fff; border-color: var(--aurora-accent); }
|
||||||
|
.wiz__btn--primary:hover { filter: brightness(1.08); }
|
||||||
|
</style>
|
||||||
@@ -131,13 +131,13 @@ const remove = async (theme) => {
|
|||||||
}
|
}
|
||||||
.themes-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
.themes-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
||||||
.themes-empty { color: var(--aurora-text-muted); font-size: 0.8125rem; }
|
.themes-empty { color: var(--aurora-text-muted); font-size: 0.8125rem; }
|
||||||
.themes-notice { padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.875rem; }
|
.themes-notice { padding: 10px 14px; border-radius: var(--aurora-radius-sm); margin-bottom: 16px; font-size: 0.875rem; }
|
||||||
.themes-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
.themes-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
||||||
|
|
||||||
.themes-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 18px; }
|
.themes-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 18px; }
|
||||||
.theme-card {
|
.theme-card {
|
||||||
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
||||||
border-radius: 14px; overflow: hidden; display: flex; flex-direction: column;
|
border-radius: var(--aurora-radius-md); overflow: hidden; display: flex; flex-direction: column;
|
||||||
}
|
}
|
||||||
.theme-card--active { border-color: var(--aurora-accent); }
|
.theme-card--active { border-color: var(--aurora-accent); }
|
||||||
.theme-card__shot {
|
.theme-card__shot {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ const submit = async () => {
|
|||||||
.add-user-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
.add-user-page h1 { margin: 0; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
||||||
|
|
||||||
.add-user-notice {
|
.add-user-notice {
|
||||||
padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.875rem;
|
padding: 10px 14px; border-radius: var(--aurora-radius-sm); margin-bottom: 16px; font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
.add-user-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
.add-user-notice--success { background: rgba(34, 197, 94, 0.12); color: #22c55e; }
|
||||||
.add-user-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
.add-user-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
||||||
@@ -135,7 +135,7 @@ const submit = async () => {
|
|||||||
display: flex; flex-direction: column; gap: 18px;
|
display: flex; flex-direction: column; gap: 18px;
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 14px;
|
border-radius: var(--aurora-radius-md);
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
.add-user-field { display: flex; flex-direction: column; gap: 6px; }
|
.add-user-field { display: flex; flex-direction: column; gap: 6px; }
|
||||||
@@ -143,7 +143,7 @@ const submit = async () => {
|
|||||||
.add-user-field em { font-weight: 400; font-style: normal; color: var(--aurora-text-muted); }
|
.add-user-field em { font-weight: 400; font-style: normal; color: var(--aurora-text-muted); }
|
||||||
.add-user-field input,
|
.add-user-field input,
|
||||||
.add-user-field select {
|
.add-user-field select {
|
||||||
padding: 9px 12px; border-radius: 8px; border: 1px solid var(--aurora-border);
|
padding: 9px 12px; border-radius: var(--aurora-radius-sm); border: 1px solid var(--aurora-border);
|
||||||
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.875rem;
|
background: var(--aurora-bg); color: var(--aurora-text); font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
.add-user-field__row { display: flex; gap: 8px; }
|
.add-user-field__row { display: flex; gap: 8px; }
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ const initials = (name) =>
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-accent);
|
background: var(--aurora-accent);
|
||||||
color: var(--aurora-accent-text);
|
color: var(--aurora-accent-text);
|
||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
@@ -331,7 +331,7 @@ const initials = (name) =>
|
|||||||
width: min(320px, 100%);
|
width: min(320px, 100%);
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -356,7 +356,7 @@ const initials = (name) =>
|
|||||||
width: 42px;
|
width: 42px;
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -383,7 +383,7 @@ const initials = (name) =>
|
|||||||
.users-notice {
|
.users-notice {
|
||||||
margin: 0 0 12px;
|
margin: 0 0 12px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
@@ -392,7 +392,7 @@ const initials = (name) =>
|
|||||||
.users-table {
|
.users-table {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
}
|
}
|
||||||
.users-table__head,
|
.users-table__head,
|
||||||
@@ -507,7 +507,7 @@ const initials = (name) =>
|
|||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -111,20 +111,20 @@ const remove = async (widget) => {
|
|||||||
.widgets-page h1 { margin: 0 0 6px; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
.widgets-page h1 { margin: 0 0 6px; font-size: 1.6rem; font-weight: 700; color: var(--aurora-text); }
|
||||||
.widgets-page__sub { margin: 0; font-size: 0.8125rem; color: var(--aurora-text-muted); max-width: 640px; }
|
.widgets-page__sub { margin: 0; font-size: 0.8125rem; color: var(--aurora-text-muted); max-width: 640px; }
|
||||||
|
|
||||||
.widgets-notice { padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.875rem; }
|
.widgets-notice { padding: 10px 14px; border-radius: var(--aurora-radius-sm); margin-bottom: 16px; font-size: 0.875rem; }
|
||||||
.widgets-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
.widgets-notice--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
||||||
|
|
||||||
.widgets-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
|
.widgets-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
|
||||||
.widgets-sidebar {
|
.widgets-sidebar {
|
||||||
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
background: var(--aurora-bg-subtle); border: 1px solid var(--aurora-border);
|
||||||
border-radius: 14px; padding: 18px;
|
border-radius: var(--aurora-radius-md); padding: 18px;
|
||||||
}
|
}
|
||||||
.widgets-sidebar h2 { font-size: 0.9375rem; margin: 0 0 10px; color: var(--aurora-text); }
|
.widgets-sidebar h2 { font-size: 0.9375rem; margin: 0 0 10px; color: var(--aurora-text); }
|
||||||
.widgets-empty { color: var(--aurora-text-muted); font-size: 0.8125rem; }
|
.widgets-empty { color: var(--aurora-text-muted); font-size: 0.8125rem; }
|
||||||
|
|
||||||
.widgets-item {
|
.widgets-item {
|
||||||
display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
||||||
padding: 8px 10px; border-radius: 8px; margin-bottom: 6px;
|
padding: 8px 10px; border-radius: var(--aurora-radius-sm); margin-bottom: 6px;
|
||||||
background: var(--aurora-bg); border: 1px solid var(--aurora-border);
|
background: var(--aurora-bg); border: 1px solid var(--aurora-border);
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
}
|
}
|
||||||
@@ -134,11 +134,11 @@ const remove = async (widget) => {
|
|||||||
.widgets-item__actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
|
.widgets-item__actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
|
||||||
.widgets-item__actions button {
|
.widgets-item__actions button {
|
||||||
border: none; background: none; color: var(--aurora-text-muted); cursor: pointer;
|
border: none; background: none; color: var(--aurora-text-muted); cursor: pointer;
|
||||||
width: 26px; height: 26px; border-radius: 6px; display: inline-flex; align-items: center; justify-content: center;
|
width: 26px; height: 26px; border-radius: var(--aurora-radius-sm); display: inline-flex; align-items: center; justify-content: center;
|
||||||
}
|
}
|
||||||
.widgets-item__actions button:hover { background: var(--aurora-bg-subtle); color: var(--aurora-text); }
|
.widgets-item__actions button:hover { background: var(--aurora-bg-subtle); color: var(--aurora-text); }
|
||||||
.widgets-item__actions select {
|
.widgets-item__actions select {
|
||||||
font-size: 0.75rem; padding: 4px 6px; border-radius: 6px;
|
font-size: 0.75rem; padding: 4px 6px; border-radius: var(--aurora-radius-sm);
|
||||||
border: 1px solid var(--aurora-border); background: var(--aurora-bg); color: var(--aurora-text);
|
border: 1px solid var(--aurora-border); background: var(--aurora-bg); color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { ref, onMounted } from 'vue';
|
|||||||
import Sidebar from './components/Sidebar.vue';
|
import Sidebar from './components/Sidebar.vue';
|
||||||
import Toolbar from './components/Toolbar.vue';
|
import Toolbar from './components/Toolbar.vue';
|
||||||
import { applyThemePalette, applyFontFamily } from '@/pages/settings/applyLiveTheme.js';
|
import { applyThemePalette, applyFontFamily } from '@/pages/settings/applyLiveTheme.js';
|
||||||
import { initWindowChrome } from './windowChrome.js';
|
import { initDashboardFrame } from './dashboardFrame.js';
|
||||||
import { getMinimizedWindows, removeMinimizedWindow } from './taskbar.js';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
serverData: {
|
serverData: {
|
||||||
@@ -25,21 +24,7 @@ const toggleMenu = () => {
|
|||||||
localStorage.setItem('aurora-menu-collapsed', collapsed.value ? '1' : '0');
|
localStorage.setItem('aurora-menu-collapsed', collapsed.value ? '1' : '0');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Every minimized window (taskbar.js persists the list in sessionStorage
|
|
||||||
// across the page loads minimizing triggers). Rendered as taskbar items at
|
|
||||||
// the bottom of every page since SiteShell mounts on all of them — clicking
|
|
||||||
// one navigates back to it and removes just that entry.
|
|
||||||
const minimizedWindows = ref([]);
|
|
||||||
const restoreWindow = (win) => {
|
|
||||||
removeMinimizedWindow(win.id);
|
|
||||||
window.location.href = win.url;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
minimizedWindows.value = getMinimizedWindows();
|
|
||||||
// Reserve bottom space for the taskbar (shell-frame.css) so page content
|
|
||||||
// stops above it instead of running underneath.
|
|
||||||
document.documentElement.classList.toggle('aurora-has-taskbar', minimizedWindows.value.length > 0);
|
|
||||||
const settings = props.serverData?.settings || {};
|
const settings = props.serverData?.settings || {};
|
||||||
// Every theme preset is its own self-contained dark-toned palette now —
|
// Every theme preset is its own self-contained dark-toned palette now —
|
||||||
// no separate light/dark mode, so this class is always on. It's kept
|
// no separate light/dark mode, so this class is always on. It's kept
|
||||||
@@ -49,7 +34,7 @@ onMounted(() => {
|
|||||||
applyThemePalette(settings.theme_preset || 'indigo');
|
applyThemePalette(settings.theme_preset || 'indigo');
|
||||||
applyCollapsed();
|
applyCollapsed();
|
||||||
applyFontFamily(settings.font_family);
|
applyFontFamily(settings.font_family);
|
||||||
initWindowChrome(props.serverData?.adminUrl);
|
initDashboardFrame();
|
||||||
// Signal the shell is live: reveals the framed content and commits to
|
// Signal the shell is live: reveals the framed content and commits to
|
||||||
// keeping native chrome hidden (the PHP failsafe stops watching once
|
// keeping native chrome hidden (the PHP failsafe stops watching once
|
||||||
// aurora-ready is present).
|
// aurora-ready is present).
|
||||||
@@ -73,74 +58,13 @@ onMounted(() => {
|
|||||||
:server-data="serverData"
|
:server-data="serverData"
|
||||||
@toggle-menu="toggleMenu"
|
@toggle-menu="toggleMenu"
|
||||||
/>
|
/>
|
||||||
<div v-if="minimizedWindows.length" class="aurora-taskbar">
|
|
||||||
<button
|
|
||||||
v-for="win in minimizedWindows"
|
|
||||||
:key="win.id"
|
|
||||||
type="button"
|
|
||||||
class="aurora-taskbar__item"
|
|
||||||
@click="restoreWindow(win)"
|
|
||||||
>
|
|
||||||
<span class="aurora-taskbar__dot" />
|
|
||||||
{{ win.title }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* Sidebar, Toolbar and the taskbar are all position:fixed, so this
|
/* Sidebar and Toolbar are both position:fixed, so this wrapper has no
|
||||||
wrapper has no layout role — it just groups them under one mounted
|
layout role — it just groups them under one mounted root. */
|
||||||
root. */
|
|
||||||
.site-shell {
|
.site-shell {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Full-width docked bar, but inset with the same gap the sidebar floats
|
|
||||||
with (not flush against the browser edges or the window above it) and
|
|
||||||
fully rounded + shadowed so it reads as its own separate surface rather
|
|
||||||
than an extension of the content frame it sits under. Page content
|
|
||||||
reserves space above it via html.aurora-has-taskbar in shell-frame.css. */
|
|
||||||
.aurora-taskbar {
|
|
||||||
position: fixed;
|
|
||||||
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2);
|
|
||||||
right: var(--aurora-sidebar-gap);
|
|
||||||
bottom: var(--aurora-sidebar-gap);
|
|
||||||
height: var(--aurora-taskbar-h);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 0 16px;
|
|
||||||
background: var(--aurora-card-bg);
|
|
||||||
border: 1px solid var(--aurora-card-border);
|
|
||||||
border-radius: var(--aurora-radius-lg);
|
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 200001;
|
|
||||||
overflow-x: auto;
|
|
||||||
transition: left 0.2s ease;
|
|
||||||
}
|
|
||||||
.aurora-taskbar__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
background: var(--aurora-bg-subtle);
|
|
||||||
border: 1px solid var(--aurora-border);
|
|
||||||
border-radius: 999px;
|
|
||||||
padding: 8px 18px 8px 10px;
|
|
||||||
color: var(--aurora-text);
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.aurora-taskbar__item:hover {
|
|
||||||
border-color: var(--aurora-accent);
|
|
||||||
}
|
|
||||||
.aurora-taskbar__dot {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #febc2e;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
|
|||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
background: var(--aurora-frame-bg, #1c1c20);
|
background: var(--aurora-frame-bg, #1c1c20);
|
||||||
border: 1px solid var(--aurora-frame-border, #34343b);
|
border: 1px solid var(--aurora-frame-border, #34343b);
|
||||||
border-radius: 14px;
|
border-radius: var(--aurora-radius-md);
|
||||||
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
|
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
@@ -171,7 +171,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
|
|||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
border: 1px solid var(--aurora-border, #27272a);
|
border: 1px solid var(--aurora-border, #27272a);
|
||||||
border-radius: 5px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
}
|
}
|
||||||
.smodal__state {
|
.smodal__state {
|
||||||
@@ -197,7 +197,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 9px;
|
border-radius: var(--aurora-radius-md);
|
||||||
}
|
}
|
||||||
.smodal__result--active { background: var(--aurora-accent-soft); }
|
.smodal__result--active { background: var(--aurora-accent-soft); }
|
||||||
.smodal__result-title {
|
.smodal__result-title {
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ const filteredAuroraNav = computed(() => {
|
|||||||
flush against the viewport edges. */
|
flush against the viewport edges. */
|
||||||
background: var(--aurora-card-bg);
|
background: var(--aurora-card-bg);
|
||||||
border: 1px solid var(--aurora-card-border);
|
border: 1px solid var(--aurora-card-border);
|
||||||
border-radius: 20px;
|
border-radius: var(--aurora-radius-lg);
|
||||||
transition: width 0.2s ease;
|
transition: width 0.2s ease;
|
||||||
z-index: 99999;
|
z-index: 99999;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -316,7 +316,7 @@ const filteredAuroraNav = computed(() => {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin: 0 12px 10px;
|
margin: 0 12px 10px;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
}
|
}
|
||||||
@@ -361,7 +361,7 @@ const filteredAuroraNav = computed(() => {
|
|||||||
.sidebar__row {
|
.sidebar__row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
margin: 0 8px;
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +393,7 @@ const filteredAuroraNav = computed(() => {
|
|||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
transition: background 0.12s ease, color 0.12s ease;
|
transition: background 0.12s ease, color 0.12s ease;
|
||||||
@@ -467,7 +467,7 @@ const filteredAuroraNav = computed(() => {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
border-radius: 6px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
margin: 0 8px;
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 34px;
|
width: 34px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
|
|||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
min-width: 240px;
|
min-width: 240px;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 10px;
|
border-radius: var(--aurora-radius-md);
|
||||||
background: var(--aurora-bg-subtle);
|
background: var(--aurora-bg-subtle);
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
@@ -141,7 +141,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
|
|||||||
.toolbar__search-kbd {
|
.toolbar__search-kbd {
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 5px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
padding: 1px 6px;
|
padding: 1px 6px;
|
||||||
background: var(--aurora-bg);
|
background: var(--aurora-bg);
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
|
|||||||
height: 34px;
|
height: 34px;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--aurora-text-muted);
|
color: var(--aurora-text-muted);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
|
|||||||
background: none;
|
background: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
}
|
}
|
||||||
.user-menu__trigger:hover {
|
.user-menu__trigger:hover {
|
||||||
@@ -125,7 +125,7 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
|
|||||||
width: 240px;
|
width: 240px;
|
||||||
background: var(--aurora-bg);
|
background: var(--aurora-bg);
|
||||||
border: 1px solid var(--aurora-border);
|
border: 1px solid var(--aurora-border);
|
||||||
border-radius: 12px;
|
border-radius: var(--aurora-radius-md);
|
||||||
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
|
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 100000;
|
z-index: 100000;
|
||||||
@@ -170,7 +170,7 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
border-radius: 8px;
|
border-radius: var(--aurora-radius-sm);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Structural setup for the takeover Dashboard.
|
||||||
|
*
|
||||||
|
* DashboardTakeover.php renders the dashboard into a separate
|
||||||
|
* #aurora-admin-dashboard-root sibling (above the hidden #wpbody), so unlike
|
||||||
|
* every other page it never sits inside #wpbody-content and never got that
|
||||||
|
* element's card frame. Wrap it in .aurora-dashboard-frame so it gets the
|
||||||
|
* same card treatment, and pull the custom admin notices
|
||||||
|
* (Notices::render_for_dashboard(), printed as a sibling just before the
|
||||||
|
* mount point) into that frame so they render as part of the card.
|
||||||
|
*
|
||||||
|
* This is the only DOM restructuring the shell does — there is no window
|
||||||
|
* chrome (title bars, traffic-light controls, minimize taskbar); that whole
|
||||||
|
* macOS-window metaphor was removed.
|
||||||
|
*/
|
||||||
|
export function initDashboardFrame() {
|
||||||
|
const dashboardRoot = document.getElementById('aurora-admin-dashboard-root');
|
||||||
|
if (!dashboardRoot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Dedupe: if SiteShell re-mounts, don't wrap a second time.
|
||||||
|
if (dashboardRoot.parentNode.querySelector('.aurora-dashboard-frame')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const frame = document.createElement('div');
|
||||||
|
frame.className = 'aurora-dashboard-frame';
|
||||||
|
dashboardRoot.parentNode.insertBefore(frame, dashboardRoot);
|
||||||
|
|
||||||
|
const notices = document.getElementById('aurora-admin-dashboard-notices');
|
||||||
|
if (notices) {
|
||||||
|
frame.appendChild(notices);
|
||||||
|
}
|
||||||
|
frame.appendChild(dashboardRoot);
|
||||||
|
}
|
||||||
+22
-179
@@ -14,13 +14,6 @@
|
|||||||
:root {
|
:root {
|
||||||
--aurora-sidebar-w: 264px;
|
--aurora-sidebar-w: 264px;
|
||||||
--aurora-toolbar-h: 56px;
|
--aurora-toolbar-h: 56px;
|
||||||
/* SiteShell.vue's taskbar, shown only while a window is minimized
|
|
||||||
(html.aurora-has-taskbar toggles the bottom space reserved for it). */
|
|
||||||
--aurora-taskbar-h: 56px;
|
|
||||||
/* Height of the strip reserved at the top of the block editor's frame
|
|
||||||
for .aurora-winbar--editor's traffic-light dots (a sibling element,
|
|
||||||
not a child of the skeleton — see windowChrome.js). */
|
|
||||||
--aurora-editor-winbar-h: 44px;
|
|
||||||
/* Space between the sidebar card and the browser's left/top/bottom
|
/* Space between the sidebar card and the browser's left/top/bottom
|
||||||
edges (Sidebar.vue) — the toolbar and #wpcontent offsets below add
|
edges (Sidebar.vue) — the toolbar and #wpcontent offsets below add
|
||||||
the same amount so nothing overlaps the floating sidebar. */
|
the same amount so nothing overlaps the floating sidebar. */
|
||||||
@@ -28,8 +21,12 @@
|
|||||||
/* Breathing room between page content and the right browser edge. */
|
/* Breathing room between page content and the right browser edge. */
|
||||||
--aurora-gutter-r: 44px;
|
--aurora-gutter-r: 44px;
|
||||||
|
|
||||||
--aurora-radius: 14px;
|
/* Corner-radius scale, one notch rounder across the UI — tune here and
|
||||||
--aurora-radius-lg: 24px;
|
every surface follows (all radii are tokenized onto this scale). */
|
||||||
|
--aurora-radius-sm: 10px; /* chips, badges, small/icon controls */
|
||||||
|
--aurora-radius-md: 14px; /* buttons, inputs, search, list rows */
|
||||||
|
--aurora-radius-lg: 20px; /* cards, panels, larger buttons */
|
||||||
|
--aurora-radius-xl: 28px; /* page frames: content card, dashboard, sidebar, editor */
|
||||||
|
|
||||||
/* Light theme */
|
/* Light theme */
|
||||||
--aurora-app-bg: #fafafa; /* zinc-50 */
|
--aurora-app-bg: #fafafa; /* zinc-50 */
|
||||||
@@ -167,15 +164,9 @@ html.aurora-ready #site-editor {
|
|||||||
position produced a visible double-edge rendering artifact right at
|
position produced a visible double-edge rendering artifact right at
|
||||||
the rounded corners. The background/gradient contrast alone is
|
the rounded corners. The background/gradient contrast alone is
|
||||||
enough to read as a distinct surface without it. */
|
enough to read as a distinct surface without it. */
|
||||||
border-radius: var(--aurora-radius-lg);
|
border-radius: var(--aurora-radius-xl);
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
transition: left 0.2s ease;
|
transition: left 0.2s ease;
|
||||||
/* Reserves a strip at the top for .aurora-winbar--editor's dots (a
|
|
||||||
sibling, not a child — see windowChrome.js) so they sit in their own
|
|
||||||
clear space instead of overlapping the editor's own logo/toolbar row.
|
|
||||||
border-box so the padding comes out of the top/left/right/bottom
|
|
||||||
inset box already defined above, rather than adding to it. */
|
|
||||||
padding-top: var(--aurora-editor-winbar-h);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
/* border-radius alone doesn't clip children — Gutenberg's own white
|
/* border-radius alone doesn't clip children — Gutenberg's own white
|
||||||
canvas background ran straight past the rounded bottom corners as a
|
canvas background ran straight past the rounded bottom corners as a
|
||||||
@@ -203,7 +194,7 @@ html.aurora-ready #wpbody-content {
|
|||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
color: var(--aurora-text);
|
color: var(--aurora-text);
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: var(--aurora-radius-lg);
|
border-radius: var(--aurora-radius-xl);
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
margin: 16px var(--aurora-gutter-r) 24px 24px;
|
margin: 16px var(--aurora-gutter-r) 24px 24px;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
@@ -250,48 +241,6 @@ html.aurora-ready body.post-php #wpbody-content {
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.aurora-ready body.block-editor-page #wpbody-content > .aurora-winbar,
|
|
||||||
html.aurora-ready body.post-new-php #wpbody-content > .aurora-winbar,
|
|
||||||
html.aurora-ready body.post-php #wpbody-content > .aurora-winbar {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SiteShell.vue's taskbar floats along the bottom edge (inset by
|
|
||||||
--aurora-sidebar-gap, same as the sidebar) only while a window is
|
|
||||||
minimized. A plain margin-bottom only guarantees a gap once the page is
|
|
||||||
scrolled all the way down — content taller than the viewport still
|
|
||||||
renders underneath the fixed taskbar on first paint, since a fixed
|
|
||||||
element doesn't reserve space from the rest of the page's flow. Instead,
|
|
||||||
cap the content box's own height to whatever's actually left between the
|
|
||||||
toolbar and the taskbar and let *it* scroll internally — the same way
|
|
||||||
the toolbar's reserved space at the top never lets content start behind
|
|
||||||
it, not just "eventually scroll clear of it". */
|
|
||||||
html.aurora-has-taskbar #wpbody-content,
|
|
||||||
html.aurora-has-taskbar .aurora-dashboard-frame {
|
|
||||||
/* #wpbody-content's base rule sets min-height: calc(100vh - toolbar-h -
|
|
||||||
40px) for the normal (no-taskbar) case — per spec, when min-height is
|
|
||||||
larger than max-height, min-height always wins and max-height is
|
|
||||||
silently ignored. Without this override the box kept sizing to that
|
|
||||||
taller min-height regardless of the taskbar, which is why the
|
|
||||||
max-height below appeared to do nothing. */
|
|
||||||
min-height: 0;
|
|
||||||
max-height: calc(
|
|
||||||
100vh - var(--aurora-toolbar-h) - 16px - 24px - var(--aurora-taskbar-h) -
|
|
||||||
var(--aurora-sidebar-gap) * 2
|
|
||||||
);
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-anchor: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The block editor's skeleton is already positioned with fixed insets
|
|
||||||
(top/left/right/bottom) rather than margin, so reserving taskbar space
|
|
||||||
is just moving its bottom inset in — no max-height/overflow trick
|
|
||||||
needed there, unlike the margin-based elements above. */
|
|
||||||
html.aurora-has-taskbar .interface-interface-skeleton,
|
|
||||||
html.aurora-has-taskbar #site-editor {
|
|
||||||
bottom: calc(24px + var(--aurora-taskbar-h) + var(--aurora-sidebar-gap) * 2) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Theme installer preview ("Add Themes" > click a theme > full "Preview &
|
/* Theme installer preview ("Add Themes" > click a theme > full "Preview &
|
||||||
Install" overlay, theme-install.php). WP core's own .wp-full-overlay
|
Install" overlay, theme-install.php). WP core's own .wp-full-overlay
|
||||||
component (shared with the Customizer, but only .theme-install-overlay
|
component (shared with the Customizer, but only .theme-install-overlay
|
||||||
@@ -355,114 +304,43 @@ html.aurora-ready .theme-install-overlay.collapsed {
|
|||||||
|
|
||||||
html.aurora-ready .theme-install-overlay .wp-full-overlay-sidebar {
|
html.aurora-ready .theme-install-overlay .wp-full-overlay-sidebar {
|
||||||
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important;
|
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important;
|
||||||
top: calc(var(--aurora-toolbar-h) + 16px + var(--aurora-editor-winbar-h)) !important;
|
top: calc(var(--aurora-toolbar-h) + 16px) !important;
|
||||||
bottom: 24px !important;
|
bottom: 24px !important;
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
border-top-left-radius: var(--aurora-radius-lg);
|
border-top-left-radius: var(--aurora-radius-xl);
|
||||||
}
|
}
|
||||||
html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
|
html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
|
||||||
top: var(--aurora-editor-winbar-h) !important;
|
top: 0 !important;
|
||||||
border-top-right-radius: var(--aurora-radius-lg);
|
border-top-right-radius: var(--aurora-radius-xl);
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* macOS-style title bar (windowChrome.js). Most pages get it injected as
|
|
||||||
the first child of #wpbody-content — negative margins cancel the 32px
|
|
||||||
padding above so it spans edge-to-edge like a real window title bar. */
|
|
||||||
.aurora-winbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.aurora-winbar--editor {
|
|
||||||
position: fixed;
|
|
||||||
/* Centered vertically within the skeleton's reserved top strip
|
|
||||||
(--aurora-editor-winbar-h), inset from its left edge to line up with
|
|
||||||
the padding every other title bar uses. */
|
|
||||||
top: calc(
|
|
||||||
var(--aurora-toolbar-h) + 16px + (var(--aurora-editor-winbar-h) - 12px) / 2
|
|
||||||
);
|
|
||||||
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px + 20px);
|
|
||||||
height: 12px;
|
|
||||||
padding: 0;
|
|
||||||
background: transparent;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
z-index: 100000;
|
|
||||||
transition: left 0.2s ease;
|
|
||||||
}
|
|
||||||
#wpbody-content > .aurora-winbar {
|
|
||||||
margin: -32px -32px 20px -32px;
|
|
||||||
padding: 14px 16px;
|
|
||||||
border-bottom: 1px solid var(--aurora-frame-border);
|
|
||||||
border-top-left-radius: var(--aurora-radius-lg);
|
|
||||||
border-top-right-radius: var(--aurora-radius-lg);
|
|
||||||
}
|
|
||||||
.aurora-winbar__crumb {
|
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--aurora-text-muted);
|
|
||||||
text-decoration: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.aurora-winbar__crumb:hover {
|
|
||||||
color: var(--aurora-text);
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot:hover {
|
|
||||||
filter: brightness(1.15);
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot--close {
|
|
||||||
background: #ff5f57;
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot--minimize {
|
|
||||||
background: #febc2e;
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot--maximize {
|
|
||||||
background: #28c840;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Dashboard bypasses #wpbody-content (DashboardTakeover.php renders
|
/* The Dashboard bypasses #wpbody-content (DashboardTakeover.php renders
|
||||||
it into a separate sibling — see windowChrome.js), so it never got the
|
it into a separate sibling — see dashboardFrame.js), so it never got the
|
||||||
card frame every other page has. windowChrome.js wraps the bar + the
|
card frame every other page has. dashboardFrame.js wraps the dashboard's
|
||||||
dashboard's mount point in this div to give it the same treatment. */
|
mount point in this div to give it the same treatment. */
|
||||||
.aurora-dashboard-frame {
|
.aurora-dashboard-frame {
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
border-radius: var(--aurora-radius-lg);
|
border-radius: var(--aurora-radius-xl);
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
margin: 16px var(--aurora-gutter-r) 24px 24px;
|
margin: 16px var(--aurora-gutter-r) 24px 24px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
/* Same unconditional height cap as #wpbody-content's base rule — this
|
/* Same unconditional height cap as #wpbody-content's base rule — this
|
||||||
element never got it, since the Dashboard bypasses #wpbody-content
|
element never got it, since the Dashboard bypasses #wpbody-content
|
||||||
entirely (a separate sibling — see windowChrome.js) and only had the
|
entirely (a separate sibling — see dashboardFrame.js). Once html/body
|
||||||
taskbar-present variant below. Once html/body were locked to
|
were locked to overflow:hidden (to kill a phantom document-level
|
||||||
overflow:hidden (to kill a phantom document-level scrollbar on
|
scrollbar on another page), the dashboard's content past the first
|
||||||
another page), the dashboard's content past the first ~1500px became
|
~1500px became completely unreachable: no internal scroll here, and
|
||||||
completely unreachable: no internal scroll here, and no document
|
no document
|
||||||
scroll left to fall back on either. */
|
scroll left to fall back on either. */
|
||||||
max-height: calc(100vh - var(--aurora-toolbar-h) - 40px);
|
max-height: calc(100vh - var(--aurora-toolbar-h) - 40px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-anchor: none;
|
overflow-anchor: none;
|
||||||
}
|
}
|
||||||
.aurora-dashboard-frame > .aurora-winbar {
|
|
||||||
padding: 14px 20px;
|
|
||||||
border-bottom: 1px solid var(--aurora-frame-border);
|
|
||||||
border-top-left-radius: var(--aurora-radius-lg);
|
|
||||||
border-top-right-radius: var(--aurora-radius-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Custom admin notices (Notices::render_for_dashboard(), reparented in
|
/* Custom admin notices (Notices::render_for_dashboard(), reparented in
|
||||||
here by windowChrome.js) — native-dark.css already themes .notice
|
here by dashboardFrame.js) — native-dark.css already themes .notice
|
||||||
elsewhere via #wpbody-content, but that stylesheet isn't loaded on the
|
elsewhere via #wpbody-content, but that stylesheet isn't loaded on the
|
||||||
Dashboard at all (Shell::is_own_page() treats index.php as one of
|
Dashboard at all (Shell::is_own_page() treats index.php as one of
|
||||||
Aurora's own pages), so it needs its own copy of the same treatment
|
Aurora's own pages), so it needs its own copy of the same treatment
|
||||||
@@ -476,41 +354,6 @@ html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
|
|||||||
margin: 16px 20px 0;
|
margin: 16px 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Yellow dot: on the Dashboard itself there's nowhere further "home" to
|
|
||||||
send it, so minimize just collapses the frame down to the title bar in
|
|
||||||
place — everywhere else, minimize navigates to the dashboard instead
|
|
||||||
(see windowChrome.js) and SiteShell.vue's taskbar offers a way back. */
|
|
||||||
html.aurora-minimized #aurora-admin-dashboard-root {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Green dot: hide Aurora's own chrome (sidebar/toolbar) and let the
|
|
||||||
content reclaim the full browser window, like restoring a real OS
|
|
||||||
window to fullscreen. */
|
|
||||||
html.aurora-maximized .sidebar,
|
|
||||||
html.aurora-maximized .toolbar {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
html.aurora-ready.aurora-maximized #wpcontent {
|
|
||||||
margin-left: 0 !important;
|
|
||||||
}
|
|
||||||
html.aurora-ready.aurora-maximized .interface-interface-skeleton,
|
|
||||||
html.aurora-ready.aurora-maximized #site-editor {
|
|
||||||
top: 0 !important;
|
|
||||||
left: 0 !important;
|
|
||||||
right: 0 !important;
|
|
||||||
bottom: 0 !important;
|
|
||||||
height: auto !important;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
html.aurora-maximized .aurora-winbar--editor {
|
|
||||||
top: calc((var(--aurora-editor-winbar-h) - 12px) / 2);
|
|
||||||
left: 20px;
|
|
||||||
}
|
|
||||||
html.aurora-maximized .aurora-taskbar {
|
|
||||||
left: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The settings page renders its own two boxed panels, so drop the outer
|
/* The settings page renders its own two boxed panels, so drop the outer
|
||||||
content frame there — leaving just those panels on the dark backdrop.
|
content frame there — leaving just those panels on the dark backdrop.
|
||||||
No background here: #wpbody-content is inset from the sidebar/gutter,
|
No background here: #wpbody-content is inset from the sidebar/gutter,
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* Tracks every "minimized" window across page loads. Aurora is a normal
|
|
||||||
* multi-page WP admin (each nav is a full page load), so a real taskbar
|
|
||||||
* needs to survive navigation — sessionStorage (tab-scoped, clears when the
|
|
||||||
* tab closes) is enough for that. Stored as a list, not a single slot —
|
|
||||||
* minimizing a second page used to silently overwrite the first one's
|
|
||||||
* entry, so only the most recent minimize ever showed up in the taskbar.
|
|
||||||
*/
|
|
||||||
const STORAGE_KEY = 'aurora-minimized-windows';
|
|
||||||
|
|
||||||
export function getMinimizedWindows() {
|
|
||||||
try {
|
|
||||||
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
||||||
const parsed = raw ? JSON.parse(raw) : [];
|
|
||||||
return Array.isArray(parsed) ? parsed : [];
|
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveMinimizedWindows(list) {
|
|
||||||
try {
|
|
||||||
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(list));
|
|
||||||
} catch {
|
|
||||||
/* sessionStorage unavailable (e.g. private mode) — minimize just won't persist */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds (or, if the same page is already minimized, replaces) an entry. */
|
|
||||||
export function addMinimizedWindow(title, url) {
|
|
||||||
const list = getMinimizedWindows().filter((w) => w.url !== url);
|
|
||||||
list.push({ id: `${Date.now()}-${Math.random().toString(36).slice(2)}`, title, url });
|
|
||||||
saveMinimizedWindows(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeMinimizedWindow(id) {
|
|
||||||
saveMinimizedWindows(getMinimizedWindows().filter((w) => w.id !== id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Best-effort readable label for the current page, used as the taskbar
|
|
||||||
* item's title. Prefers the page's own on-screen <h1> over document.title —
|
|
||||||
* WordPress's title-tag lookup walks the $submenu global to find a page's
|
|
||||||
* title, which comes up empty for Aurora's sub-app pages (SubApps.php
|
|
||||||
* registers each one normally, then immediately remove_submenu_page()s it
|
|
||||||
* to keep it out of the native menu — that breaks WP's own title lookup,
|
|
||||||
* not just this). document.title is still the fallback for pages where
|
|
||||||
* that isn't an issue (Settings, native WP pages, the Dashboard).
|
|
||||||
*/
|
|
||||||
export function currentPageTitle() {
|
|
||||||
const heading = document.querySelector('#wpbody-content h1, #aurora-admin-dashboard-root h1');
|
|
||||||
if (heading && heading.textContent.trim()) {
|
|
||||||
return heading.textContent.trim();
|
|
||||||
}
|
|
||||||
const raw = document.title || '';
|
|
||||||
return raw.split('‹')[0].trim() || 'Window';
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
/**
|
|
||||||
* Adds a macOS-style traffic-light title bar to the top of the page content.
|
|
||||||
* Three cases, in priority order:
|
|
||||||
* 1. The Dashboard — DashboardTakeover.php renders it into a separate
|
|
||||||
* #aurora-admin-dashboard-root sibling, above #wpbody (which it hides),
|
|
||||||
* to fully replace the native dashboard. Gets wrapped in a new
|
|
||||||
* .aurora-dashboard-frame div to match the card treatment
|
|
||||||
* #wpbody-content already has everywhere else.
|
|
||||||
* 2. The block editor — gets only the traffic-light controls, overlaid on
|
|
||||||
* the editor frame without a full-width titlebar surface.
|
|
||||||
* 3. Everything else — native WP pages and all of Aurora's own Vue pages,
|
|
||||||
* since each mounts its root div inside #wpbody-content. The bar is
|
|
||||||
* inserted as its first child.
|
|
||||||
*
|
|
||||||
* Red closes (navigates back to the Aurora dashboard). Yellow minimizes —
|
|
||||||
* on any page other than the dashboard, that means "save where I am and
|
|
||||||
* send me home", with SiteShell.vue's taskbar offering a way back; on the
|
|
||||||
* dashboard itself (already home) it just collapses in place instead,
|
|
||||||
* since there's nowhere further back to send it. Green hides Aurora's own
|
|
||||||
* sidebar/toolbar so the content fills the browser window. Minimized pages
|
|
||||||
* are tracked as a list (taskbar.js), not a single slot, so minimizing
|
|
||||||
* more than one shows up as separate taskbar items rather than the latest
|
|
||||||
* silently replacing the previous one.
|
|
||||||
*/
|
|
||||||
import { addMinimizedWindow, currentPageTitle } from './taskbar.js';
|
|
||||||
|
|
||||||
function buildBar(adminUrl, isDashboard) {
|
|
||||||
const bar = document.createElement('div');
|
|
||||||
bar.className = 'aurora-winbar';
|
|
||||||
|
|
||||||
const makeDot = (variant, label, onClick) => {
|
|
||||||
const dot = document.createElement('button');
|
|
||||||
dot.type = 'button';
|
|
||||||
dot.className = 'aurora-winbar__dot aurora-winbar__dot--' + variant;
|
|
||||||
dot.setAttribute('aria-label', label);
|
|
||||||
dot.title = label;
|
|
||||||
dot.addEventListener('click', onClick);
|
|
||||||
return dot;
|
|
||||||
};
|
|
||||||
|
|
||||||
const root = document.documentElement;
|
|
||||||
|
|
||||||
bar.appendChild(
|
|
||||||
makeDot('close', 'Close', () => {
|
|
||||||
window.location.href = adminUrl || '/wp-admin/';
|
|
||||||
})
|
|
||||||
);
|
|
||||||
bar.appendChild(
|
|
||||||
makeDot('minimize', 'Minimize', () => {
|
|
||||||
if (isDashboard) {
|
|
||||||
root.classList.toggle('aurora-minimized');
|
|
||||||
root.classList.remove('aurora-maximized');
|
|
||||||
} else {
|
|
||||||
addMinimizedWindow(currentPageTitle(), window.location.href);
|
|
||||||
window.location.href = adminUrl || '/wp-admin/';
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
bar.appendChild(
|
|
||||||
makeDot('maximize', 'Maximize', () => {
|
|
||||||
root.classList.toggle('aurora-maximized');
|
|
||||||
root.classList.remove('aurora-minimized');
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBlockEditorPage() {
|
|
||||||
const path = window.location.pathname;
|
|
||||||
return (
|
|
||||||
document.body.classList.contains('block-editor-page') ||
|
|
||||||
path.endsWith('/post-new.php') ||
|
|
||||||
path.endsWith('/post.php')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WP core adds a "post-type-{slug}" class to <body> on every post edit
|
|
||||||
// screen — the same signal used here to build a "back to the list" link,
|
|
||||||
// since Posts ("edit.php") and Pages ("edit.php?post_type=page") are now
|
|
||||||
// hijacked in place at their native URLs (see HijackedNativePages.php) and
|
|
||||||
// there's no single admin.php?page=... URL to hardcode anymore.
|
|
||||||
//
|
|
||||||
// The Site Editor (site-editor.php) also carries the "block-editor-page"
|
|
||||||
// body class isBlockEditorPage() matches on, but has no "post-type-*"
|
|
||||||
// class (it edits templates/template parts, not a post) — returning null
|
|
||||||
// here rather than guessing "Posts" is what keeps the crumb from showing
|
|
||||||
// up somewhere it doesn't make sense.
|
|
||||||
function editorBackLink(adminUrl) {
|
|
||||||
const match = [...document.body.classList].find((c) => c.startsWith('post-type-'));
|
|
||||||
if (!match) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const postType = match.replace('post-type-', '');
|
|
||||||
const base = adminUrl || '/wp-admin/';
|
|
||||||
if (postType === 'post') {
|
|
||||||
return { label: 'Posts', href: base + 'edit.php' };
|
|
||||||
}
|
|
||||||
if (postType === 'page') {
|
|
||||||
return { label: 'Pages', href: base + 'edit.php?post_type=page' };
|
|
||||||
}
|
|
||||||
return { label: postType, href: base + 'edit.php?post_type=' + encodeURIComponent(postType) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// theme-install.php's "Preview & Install" overlay (WP core's
|
|
||||||
// .wp-full-overlay component) needs a permanently-running observer, not a
|
|
||||||
// one-shot check, for two reasons: (1) core's own Backbone view creates it
|
|
||||||
// lazily the first time a theme is clicked, so it's missing from the
|
|
||||||
// initial DOM at initWindowChrome()'s call time; (2) every subsequent
|
|
||||||
// theme selection re-renders the overlay's contents from scratch (its own
|
|
||||||
// view.render() replaces all children to show the newly-selected theme's
|
|
||||||
// details), wiping out anything inserted into it — confirmed live: the bar
|
|
||||||
// was there after the very first click, gone after picking a second theme.
|
|
||||||
// Kept running for the page's whole lifetime rather than disconnecting
|
|
||||||
// after the first successful insert. Independent of the rest of this
|
|
||||||
// file's dedupe guard (a normal page winbar already exists in
|
|
||||||
// #wpbody-content here too; this is a second, additional bar for the
|
|
||||||
// overlay specifically, not a replacement for it).
|
|
||||||
function watchForThemeOverlay(adminUrl) {
|
|
||||||
const ensureInserted = () => {
|
|
||||||
const overlay = document.querySelector('.theme-install-overlay');
|
|
||||||
if (overlay && !overlay.querySelector('.aurora-winbar')) {
|
|
||||||
const bar = buildBar(adminUrl, false);
|
|
||||||
bar.classList.add('aurora-winbar--editor');
|
|
||||||
overlay.insertBefore(bar, overlay.firstChild);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ensureInserted();
|
|
||||||
new MutationObserver(ensureInserted).observe(document.body, { childList: true, subtree: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initWindowChrome(adminUrl) {
|
|
||||||
if (document.body.classList.contains('theme-install-php')) {
|
|
||||||
watchForThemeOverlay(adminUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.querySelector('.aurora-winbar')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dashboardRoot = document.getElementById('aurora-admin-dashboard-root');
|
|
||||||
if (dashboardRoot) {
|
|
||||||
const bar = buildBar(adminUrl, true);
|
|
||||||
const frame = document.createElement('div');
|
|
||||||
frame.className = 'aurora-dashboard-frame';
|
|
||||||
dashboardRoot.parentNode.insertBefore(frame, dashboardRoot);
|
|
||||||
frame.appendChild(bar);
|
|
||||||
// Custom admin notices (Notices::render_for_dashboard(), printed as a
|
|
||||||
// sibling right before the mount point) — reparented into the frame
|
|
||||||
// here too, so they render as part of the dashboard's own card
|
|
||||||
// instead of sitting outside it unstyled. Normally these reach the
|
|
||||||
// user via the plain admin_notices hook, but that renders inside
|
|
||||||
// #wpbody, which the Dashboard hides entirely to hide the *native*
|
|
||||||
// dashboard widgets — this is the replacement path for that one page.
|
|
||||||
const notices = document.getElementById('aurora-admin-dashboard-notices');
|
|
||||||
if (notices) frame.appendChild(notices);
|
|
||||||
frame.appendChild(dashboardRoot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBlockEditorPage()) {
|
|
||||||
const bar = buildBar(adminUrl, false);
|
|
||||||
bar.classList.add('aurora-winbar--editor');
|
|
||||||
|
|
||||||
const back = editorBackLink(adminUrl);
|
|
||||||
if (back) {
|
|
||||||
const crumb = document.createElement('a');
|
|
||||||
crumb.className = 'aurora-winbar__crumb';
|
|
||||||
crumb.href = back.href;
|
|
||||||
crumb.textContent = '← ' + back.label;
|
|
||||||
bar.appendChild(crumb);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.appendChild(bar);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wpbodyContent = document.getElementById('wpbody-content');
|
|
||||||
if (wpbodyContent) {
|
|
||||||
const bar = buildBar(adminUrl, false);
|
|
||||||
wpbodyContent.insertBefore(bar, wpbodyContent.firstChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+18
-4
@@ -2,9 +2,20 @@ import { defineConfig } from 'vite';
|
|||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import { fileURLToPath, URL } from 'node:url';
|
import { fileURLToPath, URL } from 'node:url';
|
||||||
|
|
||||||
// Deliberately simple: one entry in this first slice (dashboard). Add more
|
// Multi-entry build: one entry per admin screen (see rollupOptions.input).
|
||||||
// entries here as additional pages get rebuilt — same flat pattern each
|
// Each is enqueued as its own ES module by admin/src/Utility/Assets.php,
|
||||||
// time, no shared scoping/theme-remap layer to keep in sync across files.
|
// which also walks the manifest's `imports` chain for shared-chunk CSS.
|
||||||
|
// Rollup automatically splits code shared by 2+ entries into its own chunk;
|
||||||
|
// `vue` is pinned to a named `vendor-vue` chunk below so its hash stays
|
||||||
|
// stable across app-code changes (returning users keep it cached across
|
||||||
|
// plugin updates instead of re-downloading it every release).
|
||||||
|
//
|
||||||
|
// Sourcemaps are on by default for local debugging (the dev loop hot-patches
|
||||||
|
// app/dist into a LocalWP install). The distribution build sets
|
||||||
|
// AURORA_SOURCEMAP=false so the shipped zip doesn't carry ~1.2 MB of .map
|
||||||
|
// files that are useless to end users.
|
||||||
|
const emitSourcemaps = process.env.AURORA_SOURCEMAP !== 'false';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
root: fileURLToPath(new URL('./src', import.meta.url)),
|
root: fileURLToPath(new URL('./src', import.meta.url)),
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
@@ -16,13 +27,14 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
outDir: fileURLToPath(new URL('./dist', import.meta.url)),
|
outDir: fileURLToPath(new URL('./dist', import.meta.url)),
|
||||||
emptyOutDir: true,
|
emptyOutDir: true,
|
||||||
sourcemap: true,
|
sourcemap: emitSourcemaps,
|
||||||
manifest: true,
|
manifest: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: {
|
input: {
|
||||||
shell: fileURLToPath(new URL('./src/entries/shell.js', import.meta.url)),
|
shell: fileURLToPath(new URL('./src/entries/shell.js', import.meta.url)),
|
||||||
dashboard: fileURLToPath(new URL('./src/entries/dashboard.js', import.meta.url)),
|
dashboard: fileURLToPath(new URL('./src/entries/dashboard.js', import.meta.url)),
|
||||||
settings: fileURLToPath(new URL('./src/entries/settings.js', import.meta.url)),
|
settings: fileURLToPath(new URL('./src/entries/settings.js', import.meta.url)),
|
||||||
|
'setup-wizard': fileURLToPath(new URL('./src/entries/setup-wizard.js', import.meta.url)),
|
||||||
'menu-creator': fileURLToPath(new URL('./src/entries/menu-creator.js', import.meta.url)),
|
'menu-creator': fileURLToPath(new URL('./src/entries/menu-creator.js', import.meta.url)),
|
||||||
'admin-notices': fileURLToPath(new URL('./src/entries/admin-notices.js', import.meta.url)),
|
'admin-notices': fileURLToPath(new URL('./src/entries/admin-notices.js', import.meta.url)),
|
||||||
'role-editor': fileURLToPath(new URL('./src/entries/role-editor.js', import.meta.url)),
|
'role-editor': fileURLToPath(new URL('./src/entries/role-editor.js', import.meta.url)),
|
||||||
@@ -43,6 +55,8 @@ export default defineConfig({
|
|||||||
'bug-report': fileURLToPath(new URL('./src/entries/bug-report.js', import.meta.url)),
|
'bug-report': fileURLToPath(new URL('./src/entries/bug-report.js', import.meta.url)),
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
// Keep Vue in its own long-lived vendor chunk (see header note).
|
||||||
|
manualChunks: { 'vendor-vue': ['vue'] },
|
||||||
entryFileNames: '[name].[hash].js',
|
entryFileNames: '[name].[hash].js',
|
||||||
chunkFileNames: 'assets/[name].[hash].js',
|
chunkFileNames: 'assets/[name].[hash].js',
|
||||||
assetFileNames: 'assets/[name].[hash][extname]',
|
assetFileNames: 'assets/[name].[hash][extname]',
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ require AURORA_ADMIN_PATH . "admin/src/Shell/MenuSerializer.php";
|
|||||||
require AURORA_ADMIN_PATH . "admin/src/Shell/Shell.php";
|
require AURORA_ADMIN_PATH . "admin/src/Shell/Shell.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Pages/DashboardTakeover.php";
|
require AURORA_ADMIN_PATH . "admin/src/Pages/DashboardTakeover.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Pages/SettingsPage.php";
|
require AURORA_ADMIN_PATH . "admin/src/Pages/SettingsPage.php";
|
||||||
|
require AURORA_ADMIN_PATH . "admin/src/Pages/SetupWizard.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/DashboardData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/DashboardData.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Analytics/Analytics.php";
|
require AURORA_ADMIN_PATH . "admin/src/Analytics/Analytics.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/AnalyticsData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/AnalyticsData.php";
|
||||||
@@ -59,6 +60,8 @@ require AURORA_ADMIN_PATH . "admin/src/Login/LoginStyle.php";
|
|||||||
require AURORA_ADMIN_PATH . "admin/src/Media/SvgUploads.php";
|
require AURORA_ADMIN_PATH . "admin/src/Media/SvgUploads.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Media/MediaFolders.php";
|
require AURORA_ADMIN_PATH . "admin/src/Media/MediaFolders.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/ImageFormats/ImageFormats.php";
|
require AURORA_ADMIN_PATH . "admin/src/ImageFormats/ImageFormats.php";
|
||||||
|
require AURORA_ADMIN_PATH . "admin/src/Security/Security.php";
|
||||||
|
require AURORA_ADMIN_PATH . "admin/src/Code/CodeInjection.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/MediaFolderData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/MediaFolderData.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/BugReportData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/BugReportData.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/CompanionPluginData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/CompanionPluginData.php";
|
||||||
|
|||||||
Reference in New Issue
Block a user