Author SHA1 Message Date
NixReaperandClaude Opus 4.8 f0bc04a110 Add Security & performance settings group + hardening module
New Settings > Security & performance group (Hardening + Performance) with
toggles wired by admin/src/Security/Security.php — each gated on its own
setting, adding/removing core hooks so anything left off behaves exactly like
stock WordPress:

- Disable XML-RPC (xmlrpc_enabled false + drop X-Pingback header)
- Disable comments site-wide (close everywhere, strip post-type support,
  remove the Comments menu/dashboard-widget/toolbar node)
- Clean up <head> (generator, RSD, WLW manifest, shortlink)
- Disable emoji scripts/styles + the s.w.org dns-prefetch
- Disable oEmbeds (discovery links, host js, embed REST route, wp-embed) —
  discovery links are removed at whatever priority core hooks them (loops,
  since they can be registered at more than one)
- Heartbeat API: default / slow (60s) / disabled

New setting keys need no schema change (Settings::merge_on_save +
additionalProperties). Every toggle verified at the hook level on PHP 8.5.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 14:26:59 -05:00
NixReaperandClaude Opus 4.8 2fec4cf34b Add first-run setup wizard
Full-screen onboarding at admin.php?page=aurora-admin-setup: Welcome →
Appearance (theme + font) → Branding (logo/favicon/rename) → Features
(replacement-screen toggles) → Done. Reuses SettingsField for every control
and applyLiveTheme for instant preview; finish/skip saves via wp/v2/settings
and marks completion.

- admin/src/Pages/SetupWizard.php: hidden submenu page, disables the shell on
  its own page (aurora_admin_shell_enabled filter) + hides native chrome,
  register_activation_hook sets a one-time redirect flag, admin_init redirects
  once, and a POST /aurora-admin/v1/setup/complete route marks it done.
- app/src/pages/setup-wizard/SetupWizard.vue + entries/setup-wizard.js + vite
  input.
- Wired into aurora-admin.php + AuroraAdmin.php.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 13:55:03 -05:00
NixReaperandClaude Opus 4.8 2da3883d20 Indent settings category items under their group header
Add a small left indent to .settings__list so each group's categories read
as a nested submenu rather than sitting flush with the group header.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 13:24:17 -05:00
NixReaperandClaude Opus 4.8 b3ff365483 Round corners a notch; tokenize all radii onto an sm/md/lg/xl scale
Consolidate ~140 scattered hardcoded border-radius values (and the old
--aurora-radius/--aurora-radius-lg vars) onto one four-step scale defined in
shell-frame.css:
  --aurora-radius-sm 10px  (chips, small/icon controls; was 5-8px)
  --aurora-radius-md 14px  (buttons, inputs, search, list rows; was 9-14px)
  --aurora-radius-lg 20px  (cards, panels, larger buttons; was 15-20px)
  --aurora-radius-xl 28px  (page frames: content card, dashboard, sidebar,
                            editor; was the 24px --aurora-radius-lg)
Everything is one notch rounder, and the whole UI's roundness is now tunable
from four lines instead of 35 files.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 13:21:22 -05:00
NixReaperandClaude Opus 4.8 53ca6f62b9 Remove macOS window-chrome (traffic-light dots, minimize taskbar)
Strip the whole window metaphor as UI baggage: the traffic-light dots
injected at the top of every page, the minimize taskbar, and the
minimize/maximize state and all their CSS. windowChrome.js and taskbar.js
are gone; the only structural DOM the shell still does — wrapping the
takeover Dashboard in .aurora-dashboard-frame and reparenting its notices
into the card — moved to a focused dashboardFrame.js (initDashboardFrame()).

SiteShell.vue drops the taskbar rendering/state; shell-frame.css drops the
.aurora-winbar*/.aurora-taskbar*/minimized/maximized rules and the
--aurora-taskbar-h / --aurora-editor-winbar-h vars, and zeroes the editor
and theme-install frame offsets that reserved a top strip for the dots.
shell.js 16.4->13.4 kB. The editor "back to list" crumb lived in the bar
and was removed with it (Gutenberg's own W-logo still navigates back).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 11:44:57 -05:00
NixReaperandClaude Opus 4.8 dc2a4435c5 Remove unused CodeMirror dependencies
@codemirror/* (8 language packages) and codemirror were declared but
imported nowhere in src — leftovers from the removed File Manager and
Database Explorer. Dropped all nine; removes 30 packages from the install
(node_modules ~44 MB -> ~39 MB). Not bundled before (unused), so the built
output is unchanged. If the future custom CSS/JS editor needs an in-browser
code editor, add back the specific packages it uses at that point.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 09:57:59 -05:00
NixReaperandClaude Opus 4.8 da856dc853 Split Vue into a stable vendor chunk; make sourcemaps opt-out
- Pin `vue` to a named `vendor-vue` chunk (manualChunks) so its hash stays
  stable across app-code changes — returning users keep it cached across
  plugin releases instead of re-downloading ~31 kB gzip each update. Also
  replaces the misleadingly-named `_plugin-vue_export-helper` shared chunk.
- Gate sourcemap emission on AURORA_SOURCEMAP (default on for the local
  hot-patch dev loop; the distribution build sets it to false). Cuts a
  from-scratch dist build's app/dist from ~1.7 MB to ~502 kB by dropping
  27 .map files that ship no value to end users.
- Refresh the stale header comment (was "one entry in this first slice").

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 09:38:16 -05:00
NixReaperandClaude Opus 4.8 1c8c351654 Regroup settings into collapsible sections
Restructure the flat settingsCategories list into five top-level groups
(General, Appearance, Screens, Productivity, Add-ons), each a collapsible
nav section with persisted open/closed state. Consolidate the six
single-toggle modern_* categories (posts/pages/media/users/comments/
plugins) into one "Content tables" screen. Search now matches on group +
category + subtitle and hides empty groups. Field definitions, save flow,
and setting keys are unchanged.

settingsConfig.js exports settingsGroups plus a flattened settingsCategories
for default-seeding and deep-link lookups.

(package-lock.json: version field synced 2.16.0 -> 3.1.0 to match package.json.)

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 09:27:09 -05:00
NixReaperandClaude Opus 4.8 ce8fcc8fdd Remove uiXpress origin framing from PROJECT_STATUS
Reworded "What this project is" to describe Aurora on its own terms and
dropped the stale uixpress/ folder archaeology from the Repo section.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-12 09:26:34 -05:00
50 changed files with 1373 additions and 1371 deletions
+5 -11
View File
@@ -85,21 +85,15 @@ unless explicitly marked otherwise).)_
## What this project is
A ground-up rebuild of the "uiXpress" WordPress admin-theme plugin, relaunched
as **Aurora Admin**. The original plugin's look/feel and feature set are the
target, but **no original code is reused** — all Vue components, PHP classes,
and build tooling are freshly written. This lives in `aurora-admin-v2/` (the
earlier in-place rebrand attempt, `aurora-admin-working/`, is superseded and
no longer the active codebase).
**Aurora Admin** — a modern, fast WordPress admin interface. Real replacement
screens for the core admin (Posts, Pages, Media, Users, Comments, and more),
a full theme system with dark mode, and admin power-tools, all freshly written
from scratch (Vue components, PHP classes, and build tooling).
## Repo
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/`
(`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.
(HTTPS also available). Repo root holds `admin/`, `app/`, and `aurora-admin.php`.
`.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
+4
View File
@@ -13,6 +13,7 @@ use AuroraAdmin\Options\Settings;
use AuroraAdmin\Shell\Shell;
use AuroraAdmin\Pages\DashboardTakeover;
use AuroraAdmin\Pages\SettingsPage;
use AuroraAdmin\Pages\SetupWizard;
use AuroraAdmin\Rest\DashboardData;
use AuroraAdmin\Analytics\Analytics;
use AuroraAdmin\Rest\AnalyticsData;
@@ -45,6 +46,7 @@ use AuroraAdmin\Login\LoginStyle;
use AuroraAdmin\Media\SvgUploads;
use AuroraAdmin\Media\MediaFolders;
use AuroraAdmin\ImageFormats\ImageFormats;
use AuroraAdmin\Security\Security;
use AuroraAdmin\Rest\MediaFolderData;
use AuroraAdmin\Rest\BugReportData;
use AuroraAdmin\Rest\CompanionPluginData;
@@ -63,6 +65,7 @@ class AuroraAdmin
new Shell();
new DashboardTakeover();
new SettingsPage();
new SetupWizard();
new DashboardData();
new Analytics();
new AnalyticsData();
@@ -95,6 +98,7 @@ class AuroraAdmin
new SvgUploads();
new MediaFolders();
new ImageFormats();
new Security();
new MediaFolderData();
new BugReportData();
new CompanionPluginData();
+151
View File
@@ -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
}
}
+151
View File
@@ -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);
}
}
}
+2 -342
View File
@@ -1,22 +1,13 @@
{
"name": "aurora-admin-app",
"version": "2.16.0",
"version": "3.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "aurora-admin-app",
"version": "2.16.0",
"version": "3.1.0",
"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"
},
"devDependencies": {
@@ -70,198 +61,6 @@
"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": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
@@ -710,112 +509,6 @@
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"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": {
"version": "4.62.2",
"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==",
"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": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -1574,12 +1246,6 @@
"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": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
@@ -1692,12 +1358,6 @@
"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"
}
}
}
-9
View File
@@ -8,15 +8,6 @@
"build": "vite build"
},
"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"
},
"devDependencies": {
+10
View File
@@ -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);
}
+2 -2
View File
@@ -36,7 +36,7 @@ defineEmits(['click']);
border: none;
background: none;
cursor: pointer;
border-radius: 12px;
border-radius: var(--aurora-radius-md);
text-align: left;
}
.app-list-item:hover {
@@ -49,7 +49,7 @@ defineEmits(['click']);
width: 32px;
height: 32px;
flex-shrink: 0;
border-radius: 9px;
border-radius: var(--aurora-radius-md);
background: var(--aurora-bg-subtle);
color: var(--aurora-text-muted);
display: flex;
+5 -5
View File
@@ -94,7 +94,7 @@ const search = defineModel('search', { type: String, default: '' });
flex-shrink: 0;
height: 100%;
overflow-y: auto;
border-radius: 16px;
border-radius: var(--aurora-radius-lg);
padding: 24px 20px;
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 :deep(button) {
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);
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;
background: var(--aurora-bg-subtle);
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);
}
.app-list-shell__search input {
@@ -161,7 +161,7 @@ const search = defineModel('search', { type: String, default: '' });
flex: 1; min-width: 0;
height: 100%;
overflow-y: auto;
border-radius: 16px;
border-radius: var(--aurora-radius-lg);
padding: 28px 32px;
min-height: 480px;
box-sizing: border-box;
@@ -174,7 +174,7 @@ const search = defineModel('search', { type: String, default: '' });
text-align: center; gap: 6px;
}
.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);
display: flex; align-items: center; justify-content: center;
font-size: 22px; margin-bottom: 10px;
+2 -2
View File
@@ -139,7 +139,7 @@ const formatDate = (s) => (s ? new Date(s.replace(' ', 'T')).toLocaleString() :
<style scoped>
.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;
}
.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 pre {
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>
+3 -3
View File
@@ -190,11 +190,11 @@ const remove = async () => {
.notice-editor__row { display: flex; gap: 10px; }
.notice-editor__title {
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);
}
.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;
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__actions { display: flex; justify-content: flex-end; gap: 8px; }
.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);
}
.notice-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
+3 -3
View File
@@ -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__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--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 span { font-size: 0.8125rem; font-weight: 600; color: var(--aurora-text); }
.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;
font-family: inherit; resize: vertical;
}
.bug-report-diagnostics {
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 {
margin: 0 0 10px; font-size: 0.75rem; text-transform: uppercase;
+5 -5
View File
@@ -398,7 +398,7 @@ const rowRange = computed(() => {
width: min(320px, 100%);
min-height: 38px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
display: flex;
align-items: center;
@@ -423,7 +423,7 @@ const rowRange = computed(() => {
width: 42px;
min-height: 42px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
background: var(--aurora-bg-subtle);
display: inline-flex;
@@ -451,7 +451,7 @@ const rowRange = computed(() => {
.comments-notice {
margin: 0 0 12px;
padding: 10px 12px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
color: var(--aurora-text);
font-size: 0.78rem;
@@ -460,7 +460,7 @@ const rowRange = computed(() => {
.comments-table {
overflow: hidden;
border: 1px solid var(--aurora-frame-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
}
.comments-table__head,
@@ -636,7 +636,7 @@ const rowRange = computed(() => {
width: 28px;
height: 28px;
border: 0;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
background: transparent;
color: var(--aurora-text-muted);
cursor: pointer;
+5 -5
View File
@@ -176,7 +176,7 @@ onMounted(() => reload(range.value[0], range.value[1]));
background: var(--aurora-card-bg);
border: 1px solid var(--aurora-card-border);
color: var(--aurora-text);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
padding: 8px 12px;
font-size: 0.8125rem;
cursor: pointer;
@@ -186,7 +186,7 @@ onMounted(() => reload(range.value[0], range.value[1]));
position: absolute; right: 0; top: calc(100% + 6px);
background: var(--aurora-card-bg);
border: 1px solid var(--aurora-card-border);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
padding: 6px;
z-index: 10;
min-width: 160px;
@@ -195,14 +195,14 @@ onMounted(() => reload(range.value[0], range.value[1]));
.dash__presets button {
display: block; width: 100%; text-align: left;
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__tabs {
display: inline-flex;
gap: 2px;
background: var(--aurora-bg-subtle);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
padding: 3px;
margin-bottom: 20px;
}
@@ -214,7 +214,7 @@ onMounted(() => reload(range.value[0], range.value[1]));
}
.dash__tab {
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;
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__box {
background: var(--aurora-bg-subtle);
border-radius: 14px;
border-radius: var(--aurora-radius-md);
padding: 14px;
text-align: center;
}
@@ -102,7 +102,7 @@ const onDayClick = (cell) => {
border: 1px solid var(--aurora-card-border);
background: var(--aurora-bg-subtle);
color: var(--aurora-text-muted);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
cursor: pointer;
line-height: 1;
}
@@ -120,7 +120,7 @@ const onDayClick = (cell) => {
position: relative;
width: 100%; height: 100%;
display: flex; align-items: center; justify-content: center;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
border: 1px solid var(--aurora-card-border);
background: transparent;
padding: 0;
@@ -156,7 +156,7 @@ const onDayClick = (cell) => {
background: var(--aurora-card-bg, #1f1f23);
color: var(--aurora-text, #f4f4f5);
border: 1px solid var(--aurora-border, #2e2e33);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
padding: 12px 18px;
font-size: 0.875rem;
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__ver {
background: var(--aurora-bg-subtle);
border-radius: 12px;
border-radius: var(--aurora-radius-md);
padding: 12px 14px;
}
.sh__ver-label { font-size: 0.6875rem; color: var(--aurora-text-muted); }
@@ -31,12 +31,12 @@ defineProps({
flex-direction: column;
height: 100%;
/* 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
for most presets, so cards would nearly disappear into it otherwise. */
background: var(--aurora-card-bg-deep, var(--aurora-card-bg));
border: 1px solid var(--aurora-card-border);
border-radius: 20px;
border-radius: var(--aurora-radius-lg);
padding: 20px;
box-sizing: border-box;
}
@@ -30,7 +30,7 @@ defineProps({
<style scoped>
.pbar {
background: var(--aurora-bg-subtle);
border-radius: 12px;
border-radius: var(--aurora-radius-md);
padding: 12px 14px;
}
.pbar__top {
@@ -24,7 +24,7 @@ defineProps({
}
.statrow--boxed {
background: var(--aurora-bg-subtle);
border-radius: 14px;
border-radius: var(--aurora-radius-md);
padding: 16px 8px;
}
.statrow__value {
+2 -2
View File
@@ -122,7 +122,7 @@ const clearDone = () => {
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 10px; padding: 48px 24px; text-align: center; cursor: pointer;
border: 2px dashed var(--aurora-border);
border-radius: 14px;
border-radius: var(--aurora-radius-md);
color: var(--aurora-text-muted);
transition: border-color 0.15s, color 0.15s;
}
@@ -135,7 +135,7 @@ const clearDone = () => {
.media-upload-item {
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);
border: 1px solid var(--aurora-border);
margin-bottom: 6px; font-size: 0.875rem;
+11 -11
View File
@@ -479,7 +479,7 @@ const typeIcon = (mimeType) => {
align-items: center;
min-height: 38px;
padding: 0 16px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-accent);
color: var(--aurora-accent-text);
font-size: 0.84rem;
@@ -529,7 +529,7 @@ const typeIcon = (mimeType) => {
width: min(320px, 100%);
min-height: 38px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
display: flex;
align-items: center;
@@ -554,7 +554,7 @@ const typeIcon = (mimeType) => {
width: 42px;
min-height: 42px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
background: var(--aurora-bg-subtle);
display: inline-flex;
@@ -581,7 +581,7 @@ const typeIcon = (mimeType) => {
.media-notice {
margin: 0 0 12px;
padding: 10px 12px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
color: var(--aurora-text);
font-size: 0.78rem;
@@ -590,7 +590,7 @@ const typeIcon = (mimeType) => {
.media-grid__empty {
padding: 60px 18px;
border: 1px solid var(--aurora-frame-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
color: var(--aurora-text-muted);
font-size: 0.85rem;
@@ -603,7 +603,7 @@ const typeIcon = (mimeType) => {
}
.media-card {
border: 1px solid var(--aurora-frame-border);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
background: var(--aurora-frame-bg);
overflow: hidden;
}
@@ -688,7 +688,7 @@ const typeIcon = (mimeType) => {
width: 28px;
height: 28px;
border: 0;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
background: transparent;
color: var(--aurora-text-muted);
cursor: pointer;
@@ -733,7 +733,7 @@ const typeIcon = (mimeType) => {
width: 220px;
padding: 12px;
border: 1px solid var(--aurora-frame-border);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
background: var(--aurora-frame-bg);
}
.media-page__main {
@@ -753,7 +753,7 @@ const typeIcon = (mimeType) => {
align-items: center;
gap: 8px;
border: none;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
background: none;
padding: 6px 6px;
color: var(--aurora-text);
@@ -815,7 +815,7 @@ const typeIcon = (mimeType) => {
min-width: 150px;
overflow-y: auto;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
padding: 4px;
@@ -826,7 +826,7 @@ const typeIcon = (mimeType) => {
padding: 6px 10px;
border: none;
background: none;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
font-size: 0.78rem;
text-align: left;
+3 -3
View File
@@ -129,7 +129,7 @@ const runFromMenu = (fn) => {
.mf-tree { list-style: none; margin: 0; padding-left: 14px; }
.mf-tree:first-of-type { padding-left: 0; }
.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--active { background: var(--aurora-accent-soft); }
@@ -163,7 +163,7 @@ const runFromMenu = (fn) => {
padding: 4px;
list-style: none;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
@@ -175,7 +175,7 @@ const runFromMenu = (fn) => {
padding: 7px 10px;
border: none;
background: none;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
font-size: 0.8rem;
text-align: left;
+4 -4
View File
@@ -225,11 +225,11 @@ const toggleRole = (slug) => {
.menu-editor__row { display: flex; gap: 10px; }
.menu-editor__name {
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);
}
.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);
}
.menu-editor__section h3 {
@@ -244,13 +244,13 @@ const toggleRole = (slug) => {
border-bottom: 1px solid var(--aurora-frame-border);
}
.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;
}
.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 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);
}
.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__save {
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__fields > :last-child { border-bottom: none; }
@@ -210,6 +210,6 @@ const save = async () => {
font-size: 0.8125rem;
background: var(--aurora-bg-subtle);
padding: 2px 8px;
border-radius: 5px;
border-radius: var(--aurora-radius-sm);
}
</style>
+9 -9
View File
@@ -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-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--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-side, .nav-menus-add, .nav-menus-structure {
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 {
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__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;
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 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;
}
@@ -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 select,
.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;
}
.nav-menus-add__tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.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;
}
.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__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);
}
.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-item {
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);
font-size: 0.8125rem; color: var(--aurora-text);
}
.nav-menus-item__actions { display: flex; gap: 2px; }
.nav-menus-item__actions button {
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:disabled { opacity: 0.35; cursor: default; }
+6 -6
View File
@@ -340,7 +340,7 @@ const rowRange = computed(() => {
align-items: center;
min-height: 38px;
padding: 0 16px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-accent);
color: var(--aurora-accent-text);
font-size: 0.84rem;
@@ -390,7 +390,7 @@ const rowRange = computed(() => {
width: min(320px, 100%);
min-height: 38px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
display: flex;
align-items: center;
@@ -415,7 +415,7 @@ const rowRange = computed(() => {
width: 42px;
min-height: 42px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
background: var(--aurora-bg-subtle);
display: inline-flex;
@@ -442,7 +442,7 @@ const rowRange = computed(() => {
.pages-notice {
margin: 0 0 12px;
padding: 10px 12px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
color: var(--aurora-text);
font-size: 0.78rem;
@@ -451,7 +451,7 @@ const rowRange = computed(() => {
.pages-table {
overflow: hidden;
border: 1px solid var(--aurora-frame-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
}
.pages-table__head,
@@ -559,7 +559,7 @@ const rowRange = computed(() => {
width: 28px;
height: 28px;
border: 0;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
background: transparent;
color: var(--aurora-text-muted);
cursor: pointer;
+5 -5
View File
@@ -364,7 +364,7 @@ const versionLine = (plugin) => {
width: min(320px, 100%);
min-height: 38px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
display: flex;
align-items: center;
@@ -388,7 +388,7 @@ const versionLine = (plugin) => {
.primary-button,
.icon-button {
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
min-height: 42px;
color: var(--aurora-text);
background: var(--aurora-bg-subtle);
@@ -439,7 +439,7 @@ const versionLine = (plugin) => {
.plugins-notice {
margin: 0 0 12px;
padding: 10px 12px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
font-size: 0.78rem;
font-weight: 750;
}
@@ -454,7 +454,7 @@ const versionLine = (plugin) => {
.plugins-table {
overflow: hidden;
border: 1px solid var(--aurora-frame-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
box-shadow: none;
}
@@ -505,7 +505,7 @@ const versionLine = (plugin) => {
.plugin-row__mark {
width: 46px;
height: 46px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
display: flex;
align-items: center;
justify-content: center;
+6 -6
View File
@@ -342,7 +342,7 @@ const rowRange = computed(() => {
align-items: center;
min-height: 38px;
padding: 0 16px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-accent);
color: var(--aurora-accent-text);
font-size: 0.84rem;
@@ -392,7 +392,7 @@ const rowRange = computed(() => {
width: min(320px, 100%);
min-height: 38px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
display: flex;
align-items: center;
@@ -417,7 +417,7 @@ const rowRange = computed(() => {
width: 42px;
min-height: 42px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
background: var(--aurora-bg-subtle);
display: inline-flex;
@@ -444,7 +444,7 @@ const rowRange = computed(() => {
.posts-notice {
margin: 0 0 12px;
padding: 10px 12px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
color: var(--aurora-text);
font-size: 0.78rem;
@@ -453,7 +453,7 @@ const rowRange = computed(() => {
.posts-table {
overflow: hidden;
border: 1px solid var(--aurora-frame-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
}
.posts-table__head,
@@ -561,7 +561,7 @@ const rowRange = computed(() => {
width: 28px;
height: 28px;
border: 0;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
background: transparent;
color: var(--aurora-text-muted);
cursor: pointer;
+4 -4
View File
@@ -172,7 +172,7 @@ const changePassword = async () => {
.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-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--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
.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;
background: var(--aurora-bg-subtle);
border: 1px solid var(--aurora-border);
border-radius: 14px;
border-radius: var(--aurora-radius-md);
padding: 24px;
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 input,
.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;
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__row { display: flex; gap: 8px; }
.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;
}
</style>
+3 -3
View File
@@ -182,7 +182,7 @@ const remove = async () => {
.role-editor { display: flex; flex-direction: column; gap: 18px; }
.role-editor__row { display: flex; gap: 10px; }
.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;
}
.role-editor__name { flex: 1; font-weight: 700; }
@@ -225,7 +225,7 @@ const remove = async () => {
z-index: 20;
width: 260px;
padding: 10px 12px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
border: 1px solid var(--aurora-frame-border);
background: var(--aurora-frame-bg);
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 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);
}
.role-editor__actions .is-primary { background: var(--aurora-accent); color: #fff; }
+102 -30
View File
@@ -1,6 +1,6 @@
<script setup>
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 { applyThemePalette, applyFontFamily } from './applyLiveTheme.js';
@@ -45,6 +45,29 @@ const activeCategory = computed(
() => 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
// 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
@@ -56,6 +79,8 @@ const activeCategory = computed(
const contentEl = ref(null);
const selectCategory = (id) => {
activeId.value = id;
const g = groupOfCategory(id);
if (g) openState[g.id] = true;
const url = new URL(window.location.href);
url.searchParams.set('category', id);
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 filteredCategories = computed(() => {
const searching = computed(() => query.value.trim().length > 0);
const filteredGroups = computed(() => {
const q = query.value.trim().toLowerCase();
if (!q) return visibleCategories;
return visibleCategories.filter(
if (!q) return settingsGroups;
return settingsGroups
.map((g) => {
const groupMatch = g.title.toLowerCase().includes(q);
const categories = g.categories.filter(
(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.
@@ -172,22 +207,39 @@ const importSettings = (e) => {
<input v-model="query" type="text" placeholder="Search settings…" />
</div>
<ul class="settings__list">
<li v-for="cat in filteredCategories" :key="cat.id">
<ul class="settings__groups">
<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
type="button"
class="settings__cat"
:class="{ 'settings__cat--active': cat.id === activeId }"
@click="selectCategory(cat.id)"
>
<span class="settings__cat-icon"><span class="dashicons" :class="cat.icon" /></span>
<span class="settings__cat-text">
<span class="settings__cat-icon dashicons" :class="cat.icon" />
<span class="settings__cat-title">{{ cat.title }}</span>
<span class="settings__cat-sub">{{ cat.subtitle }}</span>
</span>
</button>
</li>
</ul>
</li>
<li v-if="!filteredGroups.length" class="settings__empty">
No settings match “{{ query }}”.
</li>
</ul>
</aside>
<!-- Right content panel -->
@@ -250,7 +302,7 @@ const importSettings = (e) => {
flex-shrink: 0;
height: 100%;
overflow-y: auto;
border-radius: 16px;
border-radius: var(--aurora-radius-lg);
padding: 24px 20px;
box-sizing: border-box;
}
@@ -262,7 +314,7 @@ const importSettings = (e) => {
.settings__actions { display: flex; gap: 4px; }
.settings__actions button {
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;
}
.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;
background: var(--aurora-bg-subtle);
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);
}
.settings__search input {
@@ -280,27 +332,47 @@ const importSettings = (e) => {
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 {
display: flex; align-items: center; gap: 12px; width: 100%;
padding: 10px; border: none; background: none; cursor: pointer;
border-radius: 12px; text-align: left; margin-bottom: 2px;
display: flex; align-items: center; gap: 10px; width: 100%;
padding: 8px 10px; border: none; background: none; cursor: pointer;
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--active { background: var(--aurora-accent-soft); }
.settings__cat-icon {
width: 34px; height: 34px; flex-shrink: 0;
border-radius: 9px; background: var(--aurora-bg-subtle);
display: flex; align-items: center; justify-content: center;
font-size: 16px; width: 18px; height: 18px; flex-shrink: 0;
color: var(--aurora-text-muted);
}
.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.875rem; font-weight: 600; color: var(--aurora-text); }
.settings__cat--active .settings__cat-title { color: var(--aurora-accent); }
.settings__cat-sub {
font-size: 0.75rem; color: var(--aurora-text-muted);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
.settings__cat-title { font-size: 0.8125rem; font-weight: 500; }
.settings__cat--active .settings__cat-title { color: var(--aurora-accent); font-weight: 600; }
.settings__empty {
padding: 12px 10px; font-size: 0.8125rem; color: var(--aurora-text-muted);
}
/* Right content — no background/border of its own, same reasoning.
@@ -313,7 +385,7 @@ const importSettings = (e) => {
flex: 1; min-width: 0;
height: 100%;
overflow-y: auto;
border-radius: 16px;
border-radius: var(--aurora-radius-lg);
padding: 28px 32px;
box-sizing: border-box;
}
@@ -330,7 +402,7 @@ const importSettings = (e) => {
.settings__saved { font-size: 0.8125rem; color: var(--aurora-text-muted); }
.settings__save {
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; }
@@ -340,7 +340,7 @@ const installCompanion = async () => {
background: var(--aurora-bg-subtle);
border: 1px solid var(--aurora-border);
color: var(--aurora-text);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
padding: 9px 12px;
font-size: 0.875rem;
}
@@ -350,14 +350,14 @@ const installCompanion = async () => {
.field__color { display: flex; align-items: center; gap: 10px; }
.field__color input[type='color'] {
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__image {
width: 160px; height: 120px;
border: 1px dashed var(--aurora-border);
border-radius: 12px;
border-radius: var(--aurora-radius-md);
background: var(--aurora-bg-subtle);
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 8px; cursor: pointer; color: var(--aurora-text-muted);
@@ -376,13 +376,13 @@ const installCompanion = async () => {
.field__repeater-remove {
flex-shrink: 0; width: 34px; border: 1px solid var(--aurora-border);
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 {
border: 1px solid var(--aurora-border);
background: var(--aurora-bg-subtle);
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); }
@@ -400,13 +400,13 @@ const installCompanion = async () => {
display: inline-flex;
background: var(--aurora-bg-subtle);
border: 1px solid var(--aurora-border);
border-radius: 9px;
border-radius: var(--aurora-radius-md);
padding: 3px;
gap: 2px;
}
.field__seg button {
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);
}
.field__seg--active { background: var(--aurora-accent); color: #fff !important; }
@@ -417,13 +417,13 @@ const installCompanion = async () => {
display: flex; flex-direction: column; align-items: center; gap: 6px;
width: 76px; padding: 10px 6px;
border: 1px solid var(--aurora-border);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
background: var(--aurora-bg-subtle);
cursor: pointer;
}
.field__theme-card--active { border-color: var(--aurora-accent); box-shadow: 0 0 0 1px var(--aurora-accent); }
.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);
display: flex; align-items: flex-end; justify-content: flex-end;
padding: 4px;
@@ -441,14 +441,14 @@ const installCompanion = async () => {
max-height: 260px; overflow-y: auto; z-index: 20;
background: var(--aurora-card-bg);
border: 1px solid var(--aurora-border);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
padding: 6px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
.field__font-item {
display: block; width: 100%; text-align: left;
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);
}
.field__font-item:hover { background: var(--aurora-bg-subtle); }
@@ -457,7 +457,7 @@ const installCompanion = async () => {
/* Companion plugin install card */
.field__companion-status { font-size: 0.8125rem; color: var(--aurora-text-muted); }
.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;
}
.field__companion-install:disabled { opacity: 0.6; cursor: default; }
+198 -115
View File
@@ -1,10 +1,18 @@
/**
* 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
* option, saved via the wp/v2/settings REST route.
*
* Categories are organized into top-level groups. Each group renders as a
* 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',
title: 'General',
@@ -47,25 +55,33 @@ export const settingsCategories = [
],
},
{
id: 'login',
title: 'Login',
subtitle: 'Customize login page appearance and security',
icon: 'dashicons-lock',
id: 'analytics',
title: 'Analytics',
subtitle: 'Built-in analytics and tracking settings',
icon: 'dashicons-chart-bar',
fields: [
{
key: 'style_login',
key: 'enable_analytics',
type: 'toggle',
label: 'Style login page',
description: 'Apply the Aurora theme to the WordPress login screen.',
label: 'Enable analytics',
description: 'Track first-party visitor analytics for the dashboard.',
default: true,
},
{
key: 'login_logo',
type: 'image',
label: 'Login logo',
description: 'Replace the WordPress logo on the login screen.',
key: 'track_admins',
type: 'toggle',
label: 'Track logged-in admins',
description: 'Include administrator visits in analytics (off by default).',
},
],
},
],
},
{
id: 'appearance',
title: 'Appearance',
icon: 'dashicons-admin-appearance',
categories: [
{
id: 'theme',
title: 'Theme',
@@ -104,7 +120,7 @@ export const settingsCategories = [
type: 'text',
label: 'Rename Aurora Admin',
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',
},
{
@@ -117,6 +133,26 @@ 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.',
},
],
},
{
id: 'menu',
title: 'Menu',
@@ -131,51 +167,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',
title: 'Pages',
subtitle: 'Page management and display preferences',
icon: 'dashicons-admin-page',
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: 'screens',
title: 'Screens',
icon: 'dashicons-desktop',
categories: [
{
id: 'dashboard',
title: 'Dashboard',
@@ -192,77 +190,78 @@ export const settingsCategories = [
],
},
{
id: 'analytics',
title: 'Analytics',
subtitle: 'Built-in analytics and tracking settings',
icon: 'dashicons-chart-bar',
id: 'content-tables',
title: 'Content tables',
subtitle: 'Choose which admin list screens use the Aurora interface',
icon: 'dashicons-editor-table',
fields: [
{
key: 'enable_analytics',
key: 'modern_posts',
type: 'toggle',
label: 'Enable analytics',
description: 'Track first-party visitor analytics for the dashboard.',
label: 'Posts',
description: 'Use the Aurora posts management interface.',
default: true,
},
{
key: 'track_admins',
key: 'modern_pages',
type: 'toggle',
label: 'Track logged-in admins',
description: 'Include administrator visits in analytics (off by default).',
label: 'Pages',
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',
type: 'toggle',
label: 'Modern media library',
label: 'Media library',
description: 'Use the Aurora media library interface.',
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',
type: 'toggle',
label: 'Modern users page',
label: 'Users',
description: 'Use the Aurora users management interface.',
default: true,
},
],
},
{
id: 'comments',
title: 'Comments',
subtitle: 'Comment management and administration',
icon: 'dashicons-admin-comments',
fields: [
{
key: 'modern_comments',
type: 'toggle',
label: 'Modern comments page',
label: 'Comments',
description: 'Use the Aurora comments management interface.',
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',
title: 'Modern Image Formats',
@@ -302,6 +301,98 @@ 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: 'add-ons',
title: 'Add-ons',
icon: 'dashicons-admin-plugins',
categories: [
{
id: 'add-ons',
title: 'Add-ons',
@@ -340,20 +431,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);
+310
View File
@@ -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>
+2 -2
View File
@@ -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-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-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 18px; }
.theme-card {
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__shot {
+3 -3
View File
@@ -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-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--error { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
@@ -135,7 +135,7 @@ const submit = async () => {
display: flex; flex-direction: column; gap: 18px;
background: var(--aurora-bg-subtle);
border: 1px solid var(--aurora-border);
border-radius: 14px;
border-radius: var(--aurora-radius-md);
padding: 24px;
}
.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 input,
.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;
}
.add-user-field__row { display: flex; gap: 8px; }
+6 -6
View File
@@ -281,7 +281,7 @@ const initials = (name) =>
align-items: center;
min-height: 38px;
padding: 0 16px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-accent);
color: var(--aurora-accent-text);
font-size: 0.84rem;
@@ -331,7 +331,7 @@ const initials = (name) =>
width: min(320px, 100%);
min-height: 38px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
display: flex;
align-items: center;
@@ -356,7 +356,7 @@ const initials = (name) =>
width: 42px;
min-height: 42px;
border: 1px solid var(--aurora-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
background: var(--aurora-bg-subtle);
display: inline-flex;
@@ -383,7 +383,7 @@ const initials = (name) =>
.users-notice {
margin: 0 0 12px;
padding: 10px 12px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
color: var(--aurora-text);
font-size: 0.78rem;
@@ -392,7 +392,7 @@ const initials = (name) =>
.users-table {
overflow: hidden;
border: 1px solid var(--aurora-frame-border);
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-frame-bg);
}
.users-table__head,
@@ -507,7 +507,7 @@ const initials = (name) =>
width: 28px;
height: 28px;
border: 0;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
background: transparent;
color: var(--aurora-text-muted);
cursor: pointer;
+5 -5
View File
@@ -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__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-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
.widgets-sidebar {
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-empty { color: var(--aurora-text-muted); font-size: 0.8125rem; }
.widgets-item {
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);
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 button {
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 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);
}
</style>
+4 -80
View File
@@ -3,8 +3,7 @@ import { ref, onMounted } from 'vue';
import Sidebar from './components/Sidebar.vue';
import Toolbar from './components/Toolbar.vue';
import { applyThemePalette, applyFontFamily } from '@/pages/settings/applyLiveTheme.js';
import { initWindowChrome } from './windowChrome.js';
import { getMinimizedWindows, removeMinimizedWindow } from './taskbar.js';
import { initDashboardFrame } from './dashboardFrame.js';
const props = defineProps({
serverData: {
@@ -25,21 +24,7 @@ const toggleMenu = () => {
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(() => {
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 || {};
// 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
@@ -49,7 +34,7 @@ onMounted(() => {
applyThemePalette(settings.theme_preset || 'indigo');
applyCollapsed();
applyFontFamily(settings.font_family);
initWindowChrome(props.serverData?.adminUrl);
initDashboardFrame();
// Signal the shell is live: reveals the framed content and commits to
// keeping native chrome hidden (the PHP failsafe stops watching once
// aurora-ready is present).
@@ -73,74 +58,13 @@ onMounted(() => {
:server-data="serverData"
@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>
</template>
<style scoped>
/* Sidebar, Toolbar and the taskbar are all position:fixed, so this
wrapper has no layout role — it just groups them under one mounted
root. */
/* Sidebar and Toolbar are both position:fixed, so this wrapper has no
layout role — it just groups them under one mounted root. */
.site-shell {
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>
+3 -3
View File
@@ -146,7 +146,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
align-self: flex-start;
background: var(--aurora-frame-bg, #1c1c20);
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);
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
@@ -171,7 +171,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
font-size: 0.6875rem;
color: var(--aurora-text-muted);
border: 1px solid var(--aurora-border, #27272a);
border-radius: 5px;
border-radius: var(--aurora-radius-sm);
padding: 2px 6px;
}
.smodal__state {
@@ -197,7 +197,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
cursor: pointer;
text-align: left;
padding: 10px 12px;
border-radius: 9px;
border-radius: var(--aurora-radius-md);
}
.smodal__result--active { background: var(--aurora-accent-soft); }
.smodal__result-title {
+5 -5
View File
@@ -276,7 +276,7 @@ const filteredAuroraNav = computed(() => {
flush against the viewport edges. */
background: var(--aurora-card-bg);
border: 1px solid var(--aurora-card-border);
border-radius: 20px;
border-radius: var(--aurora-radius-lg);
transition: width 0.2s ease;
z-index: 99999;
box-sizing: border-box;
@@ -316,7 +316,7 @@ const filteredAuroraNav = computed(() => {
gap: 8px;
margin: 0 12px 10px;
padding: 6px 10px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
color: var(--aurora-text-muted);
}
@@ -361,7 +361,7 @@ const filteredAuroraNav = computed(() => {
.sidebar__row {
display: flex;
align-items: center;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
margin: 0 8px;
}
@@ -393,7 +393,7 @@ const filteredAuroraNav = computed(() => {
width: 28px;
height: 28px;
flex-shrink: 0;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
background: var(--aurora-bg-subtle);
color: var(--aurora-text-muted);
transition: background 0.12s ease, color 0.12s ease;
@@ -467,7 +467,7 @@ const filteredAuroraNav = computed(() => {
text-decoration: none;
color: var(--aurora-text-muted);
font-size: 0.8125rem;
border-radius: 6px;
border-radius: var(--aurora-radius-sm);
margin: 0 8px;
}
+4 -4
View File
@@ -102,7 +102,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
justify-content: center;
width: 34px;
height: 34px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text-muted);
text-decoration: none;
}
@@ -120,7 +120,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
padding: 0 10px;
min-width: 240px;
border: 1px solid var(--aurora-border);
border-radius: 10px;
border-radius: var(--aurora-radius-md);
background: var(--aurora-bg-subtle);
color: var(--aurora-text-muted);
font-size: 0.8125rem;
@@ -141,7 +141,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
.toolbar__search-kbd {
font-size: 0.6875rem;
border: 1px solid var(--aurora-border);
border-radius: 5px;
border-radius: var(--aurora-radius-sm);
padding: 1px 6px;
background: var(--aurora-bg);
}
@@ -154,7 +154,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
height: 34px;
border: none;
background: none;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
cursor: pointer;
color: var(--aurora-text-muted);
}
+3 -3
View File
@@ -82,7 +82,7 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
background: none;
cursor: pointer;
padding: 6px 8px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
color: var(--aurora-text);
}
.user-menu__trigger:hover {
@@ -125,7 +125,7 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
width: 240px;
background: var(--aurora-bg);
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);
overflow: hidden;
z-index: 100000;
@@ -170,7 +170,7 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 8px;
border-radius: var(--aurora-radius-sm);
text-decoration: none;
color: var(--aurora-text);
font-size: 0.8125rem;
+35
View File
@@ -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
View File
@@ -14,13 +14,6 @@
:root {
--aurora-sidebar-w: 264px;
--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
edges (Sidebar.vue) — the toolbar and #wpcontent offsets below add
the same amount so nothing overlaps the floating sidebar. */
@@ -28,8 +21,12 @@
/* Breathing room between page content and the right browser edge. */
--aurora-gutter-r: 44px;
--aurora-radius: 14px;
--aurora-radius-lg: 24px;
/* Corner-radius scale, one notch rounder across the UI — tune here and
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 */
--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
the rounded corners. The background/gradient contrast alone is
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);
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;
/* border-radius alone doesn't clip children — Gutenberg's own white
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);
color: var(--aurora-text);
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);
margin: 16px var(--aurora-gutter-r) 24px 24px;
padding: 32px;
@@ -250,48 +241,6 @@ html.aurora-ready body.post-php #wpbody-content {
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 &
Install" overlay, theme-install.php). WP core's own .wp-full-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 {
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;
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 {
top: var(--aurora-editor-winbar-h) !important;
border-top-right-radius: var(--aurora-radius-lg);
top: 0 !important;
border-top-right-radius: var(--aurora-radius-xl);
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
it into a separate sibling — see windowChrome.js), so it never got the
card frame every other page has. windowChrome.js wraps the bar + the
dashboard's mount point in this div to give it the same treatment. */
it into a separate sibling — see dashboardFrame.js), so it never got the
card frame every other page has. dashboardFrame.js wraps the dashboard's
mount point in this div to give it the same treatment. */
.aurora-dashboard-frame {
background: var(--aurora-frame-bg);
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);
margin: 16px var(--aurora-gutter-r) 24px 24px;
box-sizing: border-box;
/* Same unconditional height cap as #wpbody-content's base rule — this
element never got it, since the Dashboard bypasses #wpbody-content
entirely (a separate sibling — see windowChrome.js) and only had the
taskbar-present variant below. Once html/body were locked to
overflow:hidden (to kill a phantom document-level scrollbar on
another page), the dashboard's content past the first ~1500px became
completely unreachable: no internal scroll here, and no document
entirely (a separate sibling — see dashboardFrame.js). Once html/body
were locked to overflow:hidden (to kill a phantom document-level
scrollbar on another page), the dashboard's content past the first
~1500px became completely unreachable: no internal scroll here, and
no document
scroll left to fall back on either. */
max-height: calc(100vh - var(--aurora-toolbar-h) - 40px);
overflow-y: auto;
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
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
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
@@ -476,41 +354,6 @@ html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
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
content frame there — leaving just those panels on the dark backdrop.
No background here: #wpbody-content is inset from the sidebar/gutter,
-57
View File
@@ -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';
}
-185
View File
@@ -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
View File
@@ -2,9 +2,20 @@ import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { fileURLToPath, URL } from 'node:url';
// Deliberately simple: one entry in this first slice (dashboard). Add more
// entries here as additional pages get rebuilt — same flat pattern each
// time, no shared scoping/theme-remap layer to keep in sync across files.
// Multi-entry build: one entry per admin screen (see rollupOptions.input).
// Each is enqueued as its own ES module by admin/src/Utility/Assets.php,
// 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({
root: fileURLToPath(new URL('./src', import.meta.url)),
plugins: [vue()],
@@ -16,13 +27,14 @@ export default defineConfig({
build: {
outDir: fileURLToPath(new URL('./dist', import.meta.url)),
emptyOutDir: true,
sourcemap: true,
sourcemap: emitSourcemaps,
manifest: true,
rollupOptions: {
input: {
shell: fileURLToPath(new URL('./src/entries/shell.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)),
'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)),
'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)),
@@ -43,6 +55,8 @@ export default defineConfig({
'bug-report': fileURLToPath(new URL('./src/entries/bug-report.js', import.meta.url)),
},
output: {
// Keep Vue in its own long-lived vendor chunk (see header note).
manualChunks: { 'vendor-vue': ['vue'] },
entryFileNames: '[name].[hash].js',
chunkFileNames: 'assets/[name].[hash].js',
assetFileNames: 'assets/[name].[hash][extname]',
+2
View File
@@ -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/Pages/DashboardTakeover.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/Analytics/Analytics.php";
require AURORA_ADMIN_PATH . "admin/src/Rest/AnalyticsData.php";
@@ -59,6 +60,7 @@ 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/MediaFolders.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/Rest/MediaFolderData.php";
require AURORA_ADMIN_PATH . "admin/src/Rest/BugReportData.php";
require AURORA_ADMIN_PATH . "admin/src/Rest/CompanionPluginData.php";