Files
aurora-wordpress-admin/PROJECT_STATUS.md
T
nixpanelandClaude Sonnet 5 8153d4397c Fix sub-app permissions bug, add Comments app, support Site Editor
- Root-cause fix for "Sorry, you are not allowed to access this page" on
  Menu Creator/Activity Log/Role Editor: remove_submenu_page() was
  corrupting WP core's user_can_access_admin_page() capability lookup.
  Sub-apps now stay registered in $submenu; MenuSerializer filters them
  out of the sidebar instead.
- Add a 6th sub-app, Comments, with a redirect from native edit-comments.php.
- Extend the window-chrome/taskbar framing to the Site Editor
  (site-editor.php), including a fix for a CSS position:fixed
  over-constraint bug that let its frame run past the viewport.
- Rewrite the taskbar from a single sessionStorage slot to a list so
  multiple minimized windows are each independently restorable.
- Extend native-dark.css coverage to the block editor's own chrome.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-03 18:48:25 -05:00

495 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Aurora Admin v2 — Project Status
_Last updated: 2026-07-03 (late session — Site Editor support, permissions bug fix, Comments sub-app, taskbar rewrite)_
## 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).
## 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.
`.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
GitLab account, then `git clone` the URL above, then `cd app && npm install`.
Claude Code conversation history does **not** sync across machines — it's
local per project-folder-per-machine. Point a fresh session at this file to
get back up to speed instead of relying on prior chat history.
## Workflow rules established
- **Always verify live in Chrome** before declaring a fix done. Use the
Chrome MCP tools (`tabs_context_mcp`, `navigate`, `computer`/screenshot,
`javascript_exec`) to inspect real DOM/computed styles rather than
guessing from source.
- **Zip packaging**: on macOS, build via `npm run build` in `app/`, `rsync`
the repo (excluding `node_modules`, `.git`, `/dist`) into a scratch staging
dir, then `zip -r -X` it into `dist/aurora-admin-v2.zip` — macOS `zip`
produces forward-slash paths natively, no path-separator corruption issue
like Windows `Compress-Archive`/PowerShell had. **Always delete the
existing zip first** (`rm -f dist/aurora-admin-v2.zip`) — `zip -r` merges
into an existing archive rather than replacing it, so stale entries (old
content hashes) silently survive otherwise. If building on Windows again,
the old PowerShell `System.IO.Compression.ZipFile` + `.Replace('\', '/')`
approach from earlier sessions still applies.
- **Fast local iteration**: the test site is LocalWP at
`/Users/kris/Local Sites/aurora/app/public/wp-content/plugins/aurora-admin`.
Instead of rezipping + manually reinstalling for every small CSS/JS tweak,
hot-patch the built files straight into that install
(`rm -rf app/dist && cp -R <repo>/app/dist app/dist`, or copy individual
files like `admin/assets/native-dark.css`) and just reload the page in
Chrome — near-instant feedback loop. Rezip properly (see above) once the
change is confirmed, so the zip artifact matches what's live-verified.
- User manually reinstalls the zip from a downloaded/attached copy when
actually deploying — **the Chrome MCP `file_upload` tool cannot push
arbitrary local files into the browser**, confirmed in an earlier session,
so that step can't be automated. (Hot-patching, above, sidesteps this for
local dev/verification.)
- **Old build caching gotcha**: WordPress serves whatever plugin files were
last installed — if the user says "didn't fix it," suspect a stale zip
still installed before suspecting the code. Verify the live script hash via
`document.querySelector('script[src*="shell"]')` + computed styles when in
doubt (done successfully this session to prove a spacing change was live).
- **Git**: local repo config only (`user.name`/`user.email` set per-repo, not
`--global`). Commit after each user-confirmed-working change, not before.
- Site under test: `http://admin.local/wp-admin/`.
## Architecture
- **PHP** (`admin/src/...`, namespaced `AuroraAdmin\...`), bootstrapped from
`aurora-admin.php` (manual `require` list, dependency order matters),
instantiated in `admin/src/App/AuroraAdmin.php`'s constructor.
- **Vue 3** app (`app/src/...`), Vite multi-entry build (`app/vite.config.js`
`rollupOptions.input`) → `manifest.json`, read by
`admin/src/Utility/Assets.php::enqueue()` which also walks the manifest's
`imports` chain to pull in shared-chunk CSS. Data reaches each Vue entry via
a `data-aurora-admin` JSON attribute on a mount div (never `wp_localize_script`).
- **Single global stylesheet**: `app/src/shell/shell-frame.css` — all
`--aurora-*` CSS variables (incl. `.aurora-dark` overrides) and the only
rules touching WP structural IDs (`#wpcontent`, `#wpbody-content`). No
element resets/utility classes leak onto native WP pages.
- **Immersive shell** (`admin/src/Shell/Shell.php` + `app/src/shell/SiteShell.vue`
+ `Sidebar.vue` + `Toolbar.vue` + `UserMenu.vue`): hides native WP chrome,
mounts a Vue sidebar/toolbar on every admin page.
- `MenuSerializer.php` converts WP's `$menu`/`$submenu` globals into JSON
for the sidebar's native-menu section — explicitly skips the
`aurora-admin` slug so Aurora's own pages aren't duplicated (they're
represented in the sidebar's own branded nav section instead).
- Sidebar has two sections: the WP-native menu list (icon-chip style,
28×28px rounded icon backgrounds, tight ~2px vertical padding per item)
and a bottom "Aurora" section (collapsible, expanded by default,
persisted via `localStorage['aurora-nav-expanded']`) styled like a
**native WP submenu** (plain indented text via `.sidebar__sublist`/
`.sidebar__sublink`, no icons) — deliberately matches how e.g. Posts'
own submenu (All Posts/Add Post/Categories/Tags) looks, per explicit user
request.
- Sidebar is `display:flex; flex-direction:column`, split into a
`.sidebar__scroll` (flex:1, scrollable — holds brand/native-list/Aurora
section) and a pinned `UserMenu` footer below it (not part of the
scrollable area, so the account card is always visible).
- `UserMenu.vue`: floating card that expands **upward** from a bottom-left
trigger (avatar+name+chevron). Card contains: user header (avatar/name/
email), links (Edit Profile → `profile.php`, Visit site, Site Settings →
`options-general.php`, Sign Out in red). No theme control here anymore —
see "Theme system" below; the old light/dark/system 3-way swatch picker
and the `dark_mode` setting it drove are both gone entirely.
- Old top-right toolbar user-dropdown and sun/moon toggle button are
**removed** — fully replaced by the bottom-left `UserMenu`.
- Sidebar is **inset**, not flush against the browser edge: fixed at
`top/left/bottom: var(--aurora-sidebar-gap)` (16px), fully rounded
corners, `background: var(--aurora-card-bg)` — floats as its own card
over the page gradient. `--aurora-sidebar-gap` is a shared CSS var
(`shell-frame.css`) that the toolbar's `left` offset and `#wpcontent`'s
`margin-left` both add too, so nothing overlaps when the gap changes.
## Theme system (rewrite — supersedes the old dark_mode 3-state model)
Went through several rounds of user-directed rework this session, landing on:
**10 fixed, named color presets + 2 flat neutrals ("Black & Grey", "White")
— no custom color picker, no separate light/dark toggle.** Each preset is
fully self-contained (its own coordinated backgrounds/cards/borders/text),
not a hue applied on top of a shared light/dark base.
- `app/src/pages/settings/themePresets.js`: `themePresets` array (10 hue-based
presets like `{ id: 'indigo', label: 'Indigo', hue: 235 }`, plus `mono` and
`white` with an explicit `palette` object instead of a hue). `buildPalette(preset)`
returns all `--aurora-*` tokens — for hue presets, computed via HSL ramps;
for the two flat presets, returned as-is. `resolvePreset(id)` looks up by id.
- The main app background (`--aurora-app-bg`) is a **3-stop gradient**, not
flat: `linear-gradient(135deg, vivid1 0%, vivid2 55%, near-black 100%)` —
two bright, saturated stops of the same hue family carry most of the bar,
dipping to a near-black anchor only in the last stretch. This exact ratio
went through several corrections against a competing plugin's ("FleekDash")
reference screenshots — a 50/50 dark-to-vivid split reads "washed out", two
competing saturated hues ~70° apart reads "muddy"; this formula was the one
the user confirmed as clean. If revisiting the gradient formula, re-check
against those reference screenshots in the conversation history rather than
re-deriving from scratch.
- `--aurora-card-bg-deep`: a newer token, one step darker than
`--aurora-card-bg`, used only by the Dashboard's `AuroraCard.vue`. Needed
because the Dashboard got its own frame background using `--aurora-frame-bg`
(see "Window chrome" below), which is close in lightness to `--aurora-card-bg`
for most presets — cards would nearly disappear into the new frame without it.
- `applyThemePalette(themePresetId)` / `applyFontFamily(family)`
(`app/src/pages/settings/applyLiveTheme.js`) — shared between the settings
page's live preview (`Settings.vue`'s `watch()`) and the real per-page-load
application (`SiteShell.vue::onMounted`). Sets each token via
`document.documentElement.style.setProperty`.
- Google Fonts picker: `app/src/pages/settings/googleFonts.js` (curated ~70
family list, not the full catalog), searchable dropdown in
`SettingsField.vue`'s `font-picker` field type, applied by injecting a
Google Fonts CSS2 `<link>` tag + setting `--aurora-font-family`.
- **Recurring bug class this session — "independently-painted gradient"**:
several elements (sidebar, toolbar, `#wpbody-content` on the settings page,
`#wpbody-content` in general) each used to paint their *own* copy of
`var(--aurora-app-bg)`. Since it's a gradient, each element computes it
independently over *its own* bounding box — a narrow tall sidebar and a
wide short toolbar get visibly different-looking slices of "the same"
gradient, creating seams at their shared edges. Fixed by making `html`/`body`
the *only* thing that paints the gradient (`background-attachment: fixed`
so it doesn't scroll away from the fixed sidebar/toolbar), and leaving
every other element transparent so that one gradient plane shows through.
**If a new seam/mismatched-rectangle bug shows up, suspect this pattern
first** — grep for `var(--aurora-app-bg)` outside `shell-frame.css`'s
`html.aurora-ready, html.aurora-ready body` rule; it shouldn't be there.
- **Dashboard takeover** (`admin/src/Pages/DashboardTakeover.php` +
`app/src/pages/dashboard/Dashboard.vue`): hijacks native `index.php` via
`in_admin_header`, hides the native `.wrap`, renders the Aurora dashboard
in its place. 12-col grid; cards are single `<section class="aurora-card">`
elements with inline `grid-column: span N` (NOT wrapped — component
attribute fallthrough for styles was unreliable). Never use unprefixed
class names on Aurora components (`.card` collided with WP core once).
- **Settings page** (`admin/src/Pages/SettingsPage.php` + `app/src/pages/
settings/Settings.vue`): owns the top-level "Aurora Admin" WP admin menu
directly via `add_menu_page` (slug `aurora-admin`). Two-box layout:
`.settings__nav` (category list) + `.settings__content` (fields), both
boxed/bordered on a darker backdrop. Field schema is declarative in
`app/src/pages/settings/settingsConfig.js`, rendered by
`app/src/pages/settings/components/SettingsField.vue` (types: text, toggle,
color, image, repeater, multiselect, segmented, remote-sites).
- **6 sub-apps** (`admin/src/Pages/SubApps.php` + one PHP feature-class pair
each + one Vue page + one Vite entry each) — reachable only via the
sidebar's Aurora nav section, not the native WP menu:
- Registered via `add_submenu_page('aurora-admin', ...)` (or `'plugins.php'`
for Plugins) and **left registered** in WP's native `$submenu` global —
**no longer hidden via `remove_submenu_page()`**. An earlier version did
call it (the standard register-but-hide trick) but that corrupts WP
core's own `user_can_access_admin_page()` capability lookup, which partly
depends on the page still being present in `$submenu` to resolve its
required capability — removing it caused "Sorry, you are not allowed to
access this page" for every user, including admins, on Menu Creator/
Activity Log/Role Editor/Comments. Root-caused and fixed this session by
deleting `hide_from_native_submenu()` entirely; duplication in the
sidebar's native-menu section is instead prevented in
`MenuSerializer::serialize()` (see below), which has no such side effect.
- All slugs prefixed `aurora-admin-*` so `Shell::is_own_page()`'s existing
`strpos($page, "aurora-admin") === 0` check covers them for free (full
custom dark theme, `native-dark.css` skipped). `MenuSerializer::serialize()`
skips any submenu slug starting `aurora-admin-` (in addition to already
skipping the `aurora-admin` top-level slug) so none of them are
duplicated in the sidebar's native-menu section — needed because most are
parented under `aurora-admin` (already skipped wholesale) but
`aurora-admin-plugins` is parented under the real `plugins.php` menu.
- Each page uses the shared two-pane layout `app/src/pages/_shared/AppListShell.vue`
(generalized from Settings.vue's box-pair CSS) + `AppListItem.vue` for
list rows.
- **Menu Creator** (`admin/src/MenuCreator/`): DB table
`aurora_admin_menus` (name/status/roles JSON/items JSON). Runtime
`admin_menu` hook (priority `PHP_INT_MAX`) applies published configs
matching the current user's roles — hides/relabels native menu items by
slug. REST: `GET/POST /menus`, `GET/PUT/DELETE /menus/:id`,
`GET /menus/native-items` (real WP menu list to build the editor from,
via `MenuSerializer::serialize()`). Reordering is stored (`order` field)
but not yet applied at runtime — CRUD + hide/relabel only so far.
- **Admin Notices** (`admin/src/Notices/`): DB table `aurora_admin_notices`
(title/message/type/roles JSON/pages JSON/dismissible/active). Runtime
`admin_notices` hook renders active, role/page-matching rows via real WP
notice markup. REST: `GET/POST /notices`, `PUT/DELETE /notices/:id`.
- **Role Editor** (`admin/src/Roles/`): no custom table — wraps core
`get_editable_roles()`/`WP_Roles` directly. Hard-codes the 5 default
roles (`administrator, editor, author, contributor, subscriber`) as
delete-protected (WP has no built-in check for this). REST:
`GET/POST /roles`, `PUT/DELETE /roles/:slug`.
- **Activity Log** (`admin/src/ActivityLog/`): DB table
`aurora_admin_activity_log`. Hooked to `save_post` (guards
`wp_is_post_autosave()`/`wp_is_post_revision()`), `before_delete_post`,
`user_register`, `profile_update`, `wp_login`, `activated_plugin`,
`deactivated_plugin`, `switch_theme`,
`update_option_aurora_admin_settings`. REST:
`GET /activity-log?action_type=&object_type=&search=&page=`.
- **Plugins** (`admin/src/Rest/PluginsData.php` + `app/src/pages/plugins/Plugins.vue`):
custom plugin management list (activate/deactivate/delete), also using
`AppListShell.vue`.
- **Comments** (`admin/src/Rest/CommentsData.php` + `app/src/pages/comments/`):
newest sub-app, `edit_posts`-gated (not `manage_options` like the others).
`SubApps::redirect_native_pages()` (`admin_init`) redirects the native
`edit-comments.php` (when hit with no `?page=` param, i.e. a direct nav
or an old bookmark/menu link) to `admin.php?page=aurora-admin-comments`.
`MenuSerializer::resolve_url()` also maps the `edit-comments.php` slug
straight to the Aurora URL so the native-menu-derived sidebar entry (for
users who can `edit_posts` but not `manage_options`, so don't see the
Aurora nav section) still lands on the Aurora page. The Dashboard's
comments card (`DashboardData.php`'s `listUrl`) was updated to point at
the same Aurora URL instead of the native one.
- **Database Explorer** (`admin/src/DatabaseExplorer/`): no custom table —
reads real `$wpdb` schema. `GET /db-tables` (SHOW TABLE STATUS),
`GET /db-tables/:table` (columns + paginated rows — table name validated
against the real `$wpdb` table list before use, never interpolated
unchecked), `POST /db-query` (raw query runner, hard-restricted
server-side to queries starting `SELECT`/`SHOW`/`DESCRIBE`/`EXPLAIN`,
single-statement only, auto-`LIMIT 200` if none given). All 3 endpoints
`manage_options`-gated. Identifier allow-listing + backtick-escaping is
the actual safety boundary (`$wpdb->prepare()` only binds values, not
identifiers).
- All 5 backend classes + `SubApps.php` are `require`'d in
`aurora-admin.php` and instantiated in `AuroraAdmin.php`.
- **Settings persistence**: `admin/src/Options/Settings.php` — partial-payload
save via `merge_on_save()` sanitize callback (merges into existing option,
doesn't overwrite). `Settings::get_safe()` strips `license_key` and remote
site passwords for use on non-admin-gated pages; `Settings::get()` (full)
only used on the manage_options-gated settings page itself.
- **Global search**: `app/src/shell/components/SearchModal.vue`, Ctrl+K,
debounced `wp/v2/search` REST calls, gated on `disable_global_search` setting.
- **Remote site switcher**: toolbar dropdown, gated on `canSwitchSites` (from
`remote_site_switcher_capability` setting) + non-empty `remote_sites`.
- **Scheduled content**: `app/src/pages/dashboard/cards/ScheduledContent.vue`
calendar cells (squares, date top-left, count centered) are clickable —
navigate to `edit.php?post_status=future&aurora_day=YYYY-MM-DD` if that day
has scheduled posts, else show a toast ("no scheduled content"). Server side:
`admin/src/Posts/ScheduledDayFilter.php` filters the `edit.php` query via
`pre_get_posts` and prints an info notice.
- **Analytics**: `admin/src/Analytics/Analytics.php` (first-party pageview
tracker, own DB table `wp_aurora_admin_pageviews`, bot detection, gated on
`enable_analytics`/`track_admins` settings) + `admin/src/Rest/AnalyticsData.php`
(aggregation REST endpoint: totals, series, device/referrer/country
breakdowns, bounce rate, active users).
- **White label**: `admin/src/WhiteLabel/WhiteLabel.php` — custom favicon,
rename plugin in Plugins list, rename top-level menu item, gettext
find/replace via `text_replacements` setting.
- **Native page dark styling**: `admin/assets/native-dark.css` (large static
sheet, all rules gated `html.aurora-dark.aurora-ready`, scoped under
`#wpbody-content`) + `admin/assets/native-enhance.js` (progressive JS
enhancement — currently only `enhanceUpdates()`, which groups the flat
Updates page sections into `.aurora-native-card` wrapper divs on
`body.update-core-php`). This session also extended coverage to media/
thickbox modals, plugin/theme card grids, and the plugin-search filter bar
(all previously untouched, so still native white regardless of theme).
Known gap: the plugin "More Details" popup renders inside an `<iframe>`
pointing at a separate WP page — CSS can't reach into it; would need JS
injection into the iframe's own document if that's ever worth fixing.
This session also added dark-theme rules for the block editor's own chrome
(`.editor-header`/`.edit-post-header`, `.interface-interface-skeleton__sidebar`
and its nested `.components-panel`/`.editor-post-status`/
`.interface-complementary-area-header`) — found by inspecting the real
screen via `computer-use` and drilling into nested elements' computed
styles, since `.interface-complementary-area` (nested inside the sidebar)
had its own explicit white background the outer rule didn't reach, leaving
a white patch below the Tags panel until it was targeted directly. The
actual post content canvas is deliberately left untouched (WYSIWYG, matches
the front-end).
## Window chrome (macOS-style title bar + taskbar)
Added earlier this session, user-requested after seeing a competing plugin's
demo; extended later the same session to cover the block editor and the Site
Editor, and the taskbar was rewritten to support multiple minimized windows.
Every page gets a traffic-light title bar; minimizing persists across a full
page navigation via a taskbar.
- `app/src/shell/windowChrome.js`: `initWindowChrome(adminUrl)`, called
unconditionally from `SiteShell.vue::onMounted` (no longer skipped on the
block editor — that special case was removed once the editor got its own
handling). Three cases, checked in priority order:
1. **Dashboard** (`#aurora-admin-dashboard-root` present) — wraps the bar +
the dashboard root in a new `.aurora-dashboard-frame` div, giving it the
same card-frame treatment (`--aurora-frame-bg`, border, radius) every
other page gets from `#wpbody-content` itself.
2. **Block editor / Site Editor** (`isBlockEditorPage()`: body has
`block-editor-page`, or the path ends `/post.php` or `/post-new.php` —
`site-editor.php` also gets `block-editor-page` on its body, so this
already covers it with no JS change needed) — appends a
`.aurora-winbar--editor` bar (dots only, no bar surface) directly to
`document.body`, since neither editor's real content container is
`#wpbody-content`.
3. **Everything else** — native WP pages and all of Aurora's own Vue pages,
inserted as the first child of `#wpbody-content`.
- Red (close): `window.location.href = adminUrl`.
- Green (maximize): toggles `html.aurora-maximized` — hides `.sidebar`/
`.toolbar`, zeroes `#wpcontent`'s `margin-left` and the editor frame's
inset, so content fills the whole browser window. Toggle again (or
minimize) to restore. Nothing persisted — resets on next page load.
- Yellow (minimize): **on the Dashboard itself**, toggles `html.aurora-minimized`
which just collapses `#aurora-admin-dashboard-root` down to the bar in
place (nowhere further "home" to send it). **On every other page**, calls
`taskbar.js`'s `addMinimizedWindow(title, url)` then navigates to the
dashboard.
- **Taskbar rewritten from a single sessionStorage slot to a list**
(`app/src/shell/taskbar.js`): minimizing a second page used to silently
overwrite the first one's entry, so only the most recent minimize ever
showed up. Now `getMinimizedWindows()`/`addMinimizedWindow()` (dedupes by
URL)/`removeMinimizedWindow(id)` operate on an array under
`sessionStorage['aurora-minimized-windows']`; `SiteShell.vue` `v-for`s over
it, rendering one `.aurora-taskbar__item` pill per entry inside a
transparent, floating `.aurora-taskbar` bar (inset by `--aurora-sidebar-gap`
on all exposed edges, rounded, its own box-shadow — went through a design
iteration from a small centered pill back to full-length per explicit user
correction, keeping only the pill shape on the individual items). Each item
is independently restorable/closable. `currentPageTitle()` prefers the
page's own on-screen `<h1>` (`#wpbody-content h1, #aurora-admin-dashboard-root h1`)
over `document.title`, since WP's title-tag generation came up empty for
Aurora's sub-app pages back when they were still `remove_submenu_page()`'d
(see the sub-apps permissions bug above) — `document.title` is still the
fallback for pages where that isn't an issue.
- **Content-behind-taskbar fix**: `html.aurora-has-taskbar` no longer just
adds `margin-bottom` (that only guarantees clearance once scrolled to the
very bottom — content taller than the viewport still rendered underneath
the fixed taskbar on first paint). Instead it caps `#wpbody-content`'s/
`.aurora-dashboard-frame`'s own height via `max-height` + `overflow-y: auto`,
same principle as the toolbar's reserved space at the top. This appeared to
do nothing at first — `#wpbody-content`'s base rule sets `min-height:
calc(100vh - toolbar-h - 40px)`, and per spec `min-height` always wins over
a smaller `max-height`; fixed by adding `min-height: 0` to the
taskbar-specific override.
- **Block editor / Site Editor framing**: neither editor renders inside
`#wpcontent`'s normal box model — each has its own fixed, full-viewport
root (`.interface-interface-skeleton` itself on `post.php`/`post-new.php`;
`#site-editor` on `site-editor.php`, where `.interface-interface-skeleton`
is merely `position: relative`, nested inside it — a reset rule puts the
nested skeleton back to a plain unpositioned child so the two frames don't
stack). `html.aurora-ready .interface-interface-skeleton, html.aurora-ready
#site-editor` in `shell-frame.css` frames whichever is the real fixed root
with the same insets/background/radius/shadow treatment `#wpbody-content`
gets elsewhere, plus `padding-top: var(--aurora-editor-winbar-h)` to
reserve a strip for `.aurora-winbar--editor`'s dots and `overflow: hidden`
so the rounded corners actually clip the editor's own white canvas
background (border-radius alone doesn't clip children). **Known
CSS-over-constraint gotcha**: WP core's `.edit-site { height: 100vh; }`
class (present on `#site-editor`) means `top`, `height`, and `bottom` are
all specified on that box at once — per spec this is over-constrained and
`bottom` silently gets recomputed from `top + height` instead of honoring
an explicit value, which is why the frame initially ran past the intended
bottom inset despite `bottom: 24px !important` being set. Fixed by adding
`height: auto !important` to the same rule so `top`/`bottom` actually
determine the box size again. **If a future feature needs to reach either
editor's own chrome**, the real containers are
`.interface-interface-skeleton` (post editor) or `#site-editor` (Site
Editor) — don't assume the normal `#wpbody-content` page structure there.
- `Shell.php::is_enabled()` no longer excludes the Site Editor screen
(`site-editor` used to be in the skip list alongside `customize`) — it
turns out to be built on the same `@wordpress/interface` package as the
block editor (`body.block-editor-page` is present on both), so the
existing block-editor handling covers it once `#site-editor` is framed.
## Key bugs fixed (root causes, in case they resurface)
- **`.card` global class collision**: original Dashboard cards used
`class="card"`, colliding with WP core's `.card { max-width: 520px }`.
Fixed by renaming to `.aurora-card*` everywhere. Never use unprefixed
class names on Aurora components.
- **Grid-column not applying on wrapped cards**: settled on unwrapped
`<section class="aurora-card" :style="{gridColumn: ...}">` — component
boundaries ate the style binding in earlier attempts.
- **Two-box settings layout**: took two wrong iterations before matching the
user's reference image. Re-confirm layout intent against a screenshot
before assuming.
- **Redundant outer frame border on settings page**: fixed with a
`body.toplevel_page_aurora-admin` override in `shell-frame.css`.
- **Dashboard submenu defaulting collapsed**: `Sidebar.vue`'s `normalize()`
URL helper didn't map the bare `/wp-admin/` root to `index.php`, so the
Dashboard section's active-state check (and thus its default-expanded
state) never matched on the dashboard itself. Fixed by normalizing empty/
query-only paths to `'index.php' + path`.
- **Aurora top-level menu appearing twice**: `SettingsPage.php`'s
`add_menu_page('aurora-admin', ...)` naturally appears in WP's native
`$menu` global. Since it's now also shown in the sidebar's dedicated Aurora
nav section, `MenuSerializer::serialize()` explicitly skips slug
`aurora-admin` to avoid the duplicate.
- **Browser automation can't install plugins**: the Chrome MCP `file_upload`
tool only accepts files already "shared with the session" (attachments/
connected folders) — local build output on disk doesn't qualify. Confirmed
this session; the user must manually reinstall the zip every time (though
see "Fast local iteration" above for the hot-patch workaround used for
verification during dev).
- **Independently-painted gradient seams** (sidebar/toolbar/settings-page
`#wpbody-content` each showing a visibly different slice of "the same"
background gradient): see the theme-system section above — root cause was
multiple elements each painting their own copy of a gradient-valued
`var(--aurora-app-bg)` instead of one element painting it and the rest
staying transparent.
- **Block editor content rendering underneath the sidebar**: Gutenberg's
`.interface-interface-skeleton` is `position: fixed; inset: 0`, completely
bypassing the `margin-left` that pushes every other page's `#wpcontent`
over — see the "Window chrome" block editor exception above for the full
mechanism and the fix.
- **`zip -r` merging into a stale archive**: rebuilding the deployable zip
without first deleting the old one left old-hash asset filenames mixed
into the new zip (macOS `zip -r` appends/merges rather than replacing).
Always `rm -f` the zip before rebuilding.
- **`remove_submenu_page()` corrupting WP's own capability check**: root
cause of "Sorry, you are not allowed to access this page" on Menu Creator/
Activity Log/Role Editor/Comments — see the sub-apps bullet above. Also
broke `document.title` on those pages, which is why `taskbar.js`'s
`currentPageTitle()` prefers the on-page `<h1>` instead. **If a future
custom admin page needs to be kept out of the native menu while staying
reachable and capability-checked, filter it out at the menu-serialization
layer (like `MenuSerializer.php` does), never with `remove_submenu_page()`.**
- **`min-height`/`max-height` conflict silently no-oping a fix**: per spec,
when `min-height` is larger than `max-height`, `min-height` always wins and
`max-height` is ignored outright — this is why the taskbar-overlap fix
first appeared to do nothing (see Window chrome section above).
- **`position: fixed` over-constraint silently ignoring an explicit `bottom`**:
when `top`, `height`, and `bottom` are all specified on a fixed-position
box, the spec has `bottom` get silently recomputed from `top + height`
rather than honored — root cause of the Site Editor frame running past the
viewport despite an explicit `bottom: 24px !important` (see Window chrome
section above).
## Not-yet-done (deferred, no active request)
- Full field sets for settings categories beyond General/Analytics/White
Label (original plugin had more).
- Extending `native-enhance.js`/`native-dark.css` coverage to more native
surfaces — the block editor's own chrome, Widgets screen, Customizer.
Media/thickbox modals and plugin/theme card grids were added this session;
the plugin "More Details" popup specifically can't be reached (it's an
`<iframe>` — see native page dark styling notes above).
- Porting the real license-key activation flow (built previously in the old
`aurora-admin-working` project, not yet ported to v2 — currently just a
text field).
- Menu Creator: stored item `order` field isn't applied at runtime yet
(hide/relabel work; reordering doesn't).
- No automated tests anywhere in the project — all verification has been
manual, live-in-Chrome, per the established workflow rule above.
## Current state
No task in progress. Earlier this session rebuilt the entire theming system
(fixed color presets, gradient backgrounds, "independently-painted gradient"
seam bugs) and added the macOS-style window chrome + taskbar feature
end-to-end (pushed as commits `4a547d2`/`b0b0a99`). Later the same session:
root-caused and fixed the Menu Creator/Activity Log/Role Editor "Sorry, you
are not allowed to access this page" bug (was `remove_submenu_page()`
corrupting WP's own capability lookup); added a 6th sub-app, Comments; fixed
a white-patch bug in the block editor's dark-themed sidebar; rewrote the
taskbar from a single sessionStorage slot to a list supporting multiple
minimized windows; and extended the window-chrome/taskbar framing to the
Site Editor (`site-editor.php`), including tracking down a CSS
over-constraint bug (`top`+`height`+`bottom` all set on a fixed-position box
silently ignoring `bottom`) that was making its frame run past the viewport.
All of it was live-verified in Chrome against the LocalWP site. This batch
of changes was uncommitted at the point this doc was last updated — commit
and push it as one of the next steps if not already done by the time this is
read.