Files
aurora-wordpress-admin/PROJECT_STATUS.md
T

411 lines
26 KiB
Markdown
Raw Normal View History

2026-07-03 02:53:29 -05:00
# Aurora Admin v2 — Project Status
_Last updated: 2026-07-03 (evening session — theme system rebuild + window chrome)_
2026-07-03 02:53:29 -05:00
## 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.
2026-07-03 02:53:29 -05:00
## 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.
2026-07-03 02:53:29 -05:00
- 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
2026-07-03 02:53:29 -05:00
`--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.
2026-07-03 02:53:29 -05:00
- **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.
2026-07-03 02:53:29 -05:00
- **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).
2026-07-03 02:53:29 -05:00
- **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).
- **5 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', ...)` then immediately
`remove_submenu_page()`'d on a late `admin_menu` hook — the
register-but-hide trick: real page/capability/URL, but never appears in
WP's native `$submenu` global (so `MenuSerializer` never sees them,
nothing to filter there).
- 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).
- 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`. **Known bug, unresolved**: unlike the other sub-apps,
Menu Creator/Activity Log/Role Editor currently throw WordPress's native
"Sorry, you are not allowed to access this page" for the logged-in admin
user when navigated to directly, while Settings/Plugins/Dashboard work
fine — likely a capability-check mismatch in how those three register
their submenu pages vs. the working ones. Not yet root-caused; a
background investigation task was spawned for it but not completed this
session — check for it before re-investigating from scratch.
- **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`.
2026-07-03 02:53:29 -05:00
- **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.
## Window chrome (macOS-style title bar + taskbar)
Added this session, user-requested after seeing a competing plugin's demo.
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 from
`SiteShell.vue::onMounted` (skipped on the block editor — see below).
Injects a `.aurora-winbar` div (3 dot buttons) as the first child of
`#wpbody-content` — the one container shared by *every* page Aurora
manages, native WP pages and all of Aurora's own Vue pages alike, since
each Vue entry mounts its root div there. **Exception**: the Dashboard
(`DashboardTakeover.php`) renders into a separate `#aurora-admin-dashboard-root`
sibling *above* `#wpbody` (which it hides) to fully replace the native
dashboard — `#wpbody-content` is empty/collapsed there. `windowChrome.js`
detects this and instead wraps the bar + `#aurora-admin-dashboard-root` in
a new `.aurora-dashboard-frame` div, giving the Dashboard the same
card-frame treatment (`--aurora-frame-bg`, border, radius) every other
page already gets from `#wpbody-content` itself.
- Red (close): `window.location.href = adminUrl`.
- Green (maximize): toggles `html.aurora-maximized` — hides `.sidebar`/
`.toolbar`, zeroes `#wpcontent`'s `margin-left` and the block editor
skeleton's `left`, 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 `setMinimizedWindow(title, url)` (persists `{title, url}` in
`sessionStorage`, tab-scoped) then navigates to the dashboard. Only one
minimized window is tracked at a time — this is "minimize sends you home
with a way back," not a real window manager.
- `SiteShell.vue` reads `taskbar.js`'s `getMinimizedWindow()` on every mount
(so the taskbar shows up on whatever page you're on after minimizing) and
renders a **full-width docked bar** at the bottom with one pill-shaped
item; clicking it clears the sessionStorage entry and navigates back to
the stored URL. `html.aurora-has-taskbar` (toggled alongside) reserves
bottom margin on `#wpbody-content`/`.aurora-dashboard-frame` equal to
`--aurora-taskbar-h` so page content stops above the bar instead of
running underneath it. Went through two design iterations (small centered
floating pill → back to a full-length bar per explicit user correction —
the pill-shaped *item* stayed, just not as the whole bar).
- **Block editor exception**: Gutenberg (`post.php`/`post-new.php`) doesn't
render inside `#wpcontent`'s normal box model at all — its
`.interface-interface-skeleton` is `position: fixed; inset: 0`, anchored to
the viewport independent of any margin/padding on ancestors. `SiteShell.vue`
detects `document.body.classList.contains('block-editor-page')` and: (a)
skips rendering Aurora's own `<Toolbar>` (the editor has its own,
equivalent one — stacking both left a gradient seam between them), (b)
skips `initWindowChrome()` entirely (`#wpbody-content` is invisible/
collapsed there, injecting into it would be dead clutter), (c) insets the
skeleton itself via `left`/`top` in `shell-frame.css` so it doesn't render
underneath the sidebar. **If a future feature needs to reach the block
editor's own chrome**, its real container is `.interface-interface-skeleton`,
not `#wpbody-content` — don't assume the normal page structure there.
2026-07-03 02:53:29 -05:00
## 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.
2026-07-03 02:53:29 -05:00
- **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.
2026-07-03 02:53:29 -05:00
## 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).
2026-07-03 02:53:29 -05:00
- 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).
- **Unresolved from this session**: Menu Creator/Activity Log/Role Editor
throw "Sorry, you are not allowed to access this page" for the admin user
— see the Plugins sub-app bullet above. A background investigation task
was spawned (`task_f8e56f60` at spawn time) but its outcome isn't recorded
here — check whether it landed before re-investigating.
- 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. This session rebuilt the entire theming system (fixed
color presets replacing the old light/dark toggle, gradient backgrounds,
several "independently-painted gradient" seam bugs), added the macOS-style
window chrome + taskbar feature end-to-end, and extended native-page dark
styling coverage. All of it was live-verified in Chrome against the LocalWP
site and is pushed to `origin/main` (commit `4a547d2` at session end — a
single large commit covering the whole session's work, since it wasn't
broken into incremental commits along the way). The one known open issue is
the Menu Creator/Activity Log/Role Editor permissions bug noted above.