Files
aurora-wordpress-admin/app/src/shell/shell-frame.css
T
nixpanelandClaude Sonnet 5 d8bf1ae049 Fix Admin Notices not showing on the Dashboard (v2.4.2)
admin_notices fires everywhere, but prints inside #wpbody, which
DashboardTakeover hides entirely on the Dashboard (to hide the *native*
dashboard, not ours) — notices went down with it as collateral damage.
Notices::render_for_dashboard() now renders directly inside the visible
dashboard frame instead, called from DashboardTakeover::render_mount();
the normal admin_notices path bails on the Dashboard so it isn't
rendered twice.

Second, independent bug found along the way: wp-admin/js/common.js
unconditionally relocates every .notice element on the page to right
after the page's <h1>, regardless of where it was placed server-side —
without opting out, it would've silently moved our notice right back
into the hidden #wpbody. Used core's own documented `below-h2` class to
opt out, only for the dashboard render path.

Verified live: notice now shows correctly inside the dashboard frame
with proper dark styling, and dismisses correctly.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-04 10:27:58 -05:00

448 lines
20 KiB
CSS

/*
* The ONLY global stylesheet in the plugin. Every rule here either defines
* an --aurora-* theme variable or targets a specific WordPress structural ID
* to frame the native content. No element/tag resets, no utility classes —
* so it cannot leak onto or restyle WordPress's own page content the way the
* old plugin's Tailwind preflight did.
*
* Theme colors live here as plain CSS variables we fully control. Dark mode
* is a single class on <html> (.aurora-dark) that swaps the variable values.
*/
/* Palette carried over from the original plugin's design tokens: a zinc
neutral scale with a blue/indigo accent, large rounded surfaces. */
: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. */
--aurora-sidebar-gap: 16px;
/* Breathing room between page content and the right browser edge. */
--aurora-gutter-r: 44px;
--aurora-radius: 14px;
--aurora-radius-lg: 24px;
/* Light theme */
--aurora-app-bg: #fafafa; /* zinc-50 */
/* Flat fallback for the handful of consumers that need a solid color
(--aurora-app-bg itself may be a gradient once a theme preset applies). */
--aurora-app-bg-solid: #fafafa;
--aurora-bg: #ffffff; /* frame */
--aurora-card-bg: #fafafa; /* zinc-50 */
/* Dashboard cards specifically (AuroraCard.vue) — a step further from
--aurora-frame-bg than --aurora-card-bg so they read as distinct
surfaces against the Dashboard's own frame, not a near-identical tone. */
--aurora-card-bg-deep: #f0f0f2;
--aurora-bg-subtle: #f4f4f5; /* zinc-100 */
--aurora-text: #18181b; /* zinc-900 */
--aurora-text-muted: #71717a; /* zinc-500 */
--aurora-border: #e4e4e7; /* zinc-200 */
--aurora-card-border: #ececef;
--aurora-frame-bg: #ffffff; /* native-page content panel */
--aurora-frame-border: #e0e0e3;
--aurora-accent: rgb(71 114 250);
--aurora-accent-soft: rgb(71 114 250 / 0.1);
--aurora-accent-text: #ffffff;
/* Overridden by the font-picker setting (see SiteShell.vue::applyFontFamily);
this is the fallback when no Google Font has been chosen. */
--aurora-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Minified menu: the toolbar's collapse button toggles this class; every
layout offset derives from --aurora-sidebar-w, so this one override
reflows the toolbar and content automatically. */
html.aurora-collapsed {
--aurora-sidebar-w: 68px;
}
html.aurora-dark {
/* Dark theme — the immersive near-black look of the original */
--aurora-app-bg: #09090b; /* zinc-950 */
--aurora-app-bg-solid: #09090b;
--aurora-bg: #18181b; /* zinc-900 frame */
--aurora-card-bg: #1f1f23; /* slightly elevated */
--aurora-card-bg-deep: #131316;
--aurora-bg-subtle: #27272a; /* zinc-800 */
--aurora-text: #f4f4f5; /* zinc-100 */
--aurora-text-muted: #a1a1aa; /* zinc-400 */
--aurora-border: #27272a; /* zinc-800 */
--aurora-card-border: #2e2e33;
--aurora-frame-bg: #1c1c20; /* slightly elevated panel */
--aurora-frame-border: #34343b;
--aurora-accent: rgb(125 158 255);
--aurora-accent-soft: rgb(125 158 255 / 0.14);
}
/* --- Framing: only applies once the Vue shell has signalled ready --- */
html.aurora-ready,
html.aurora-ready body {
/* !important: WP core ships `body.js.block-editor-page { background:
#fff }` on the block editor, which has higher specificity (two
classes) than this selector (one) despite this having more type
selectors — CSS specificity compares class count before type count.
Without !important that rule wins and paints body solid white,
hiding the gradient completely on that page (everywhere else this
conflict doesn't exist, so it was never needed until now). */
background: var(--aurora-app-bg) !important;
/* Fixed so the gradient stays pinned to the viewport instead of
scrolling with document height — the sidebar/toolbar are also
position:fixed and paint no background of their own (see
Sidebar.vue/Toolbar.vue), so this one gradient plane has to line up
with them at every scroll position to read as a single unified
background instead of a seam between "sidebar" and "page". */
background-attachment: fixed;
font-family: var(--aurora-font-family);
/* The sidebar/toolbar are position:fixed and every page's real content
now scrolls internally within its own frame (#wpbody-content or
.aurora-dashboard-frame, both capped to the viewport with their own
overflow-y: auto below) — so the document itself is never meant to
scroll. Some native pages (Add Plugins' plugin-card grid is the one
that surfaced this) leave a huge dead scrollable area at the document
level — a WP/browser quirk around lazily-rendered content reserving
scroll space against the page rather than the inner container — which
showed up as being able to scroll the whole window down to a big
empty gap below the frame. Locking the document's own scroll removes
that dead space outright, regardless of what's causing it. */
overflow: hidden;
}
/* !important here defeats WordPress's own responsive #wpcontent margin
rules (.auto-fold / folded menu states live in media queries at equal
specificity). This is positioning the frame, not restyling content.
The toolbar clearance lives here (on #wpcontent, which holds everything)
rather than on #wpbody, so content rendered above #wpbody — like the
takeover dashboard — also clears the fixed toolbar. */
html.aurora-ready #wpcontent {
margin-left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2) !important;
padding-left: 0 !important;
padding-top: var(--aurora-toolbar-h);
transition: margin-left 0.2s ease;
}
/* The block editor (Gutenberg) doesn't live inside #wpcontent's normal
box model — it renders its own fixed, full-viewport root, completely
independent of the margin-left above. Left unchecked it spans the full
viewport and renders underneath the (higher z-index) sidebar and
toolbar. Framed the same way #wpbody-content is everywhere else — same
insets, same card background/border/radius — just expressed as
fixed-position offsets instead of margin, since this element can't
participate in normal document flow.
Two different pages, two different fixed roots, both matched here:
- post.php/post-new.php: .interface-interface-skeleton itself is
position:fixed, inset:0.
- site-editor.php: .interface-interface-skeleton is only
position:relative, nested inside #site-editor, which is the actual
position:fixed, inset:0 element there — the rule below with
"#site-editor .interface-interface-skeleton" resets the nested one
back to a plain unpositioned child so the two frames don't stack. */
html.aurora-ready .interface-interface-skeleton,
html.aurora-ready #site-editor {
top: calc(var(--aurora-toolbar-h) + 16px) !important;
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important;
right: var(--aurora-gutter-r) !important;
bottom: 24px !important;
/* WP core's own .edit-site class (also present on #site-editor) sets
height: 100vh. A position:fixed box with top, height, AND bottom all
specified is over-constrained — per spec, 'bottom' is then silently
recomputed from top+height instead of honoring the value here, which
is exactly why the frame ran past the bottom of the viewport instead
of stopping at the inset above. Forcing height back to auto lets
top+bottom actually determine the box's size again. */
height: auto !important;
background: var(--aurora-frame-bg);
/* No border — an asymmetric one (3 sides, one "none") combined with
border-radius and this element's sub-pixel calc()-derived fixed
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);
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
hard square edge without this. Floating UI (block toolbars, popovers)
portals to document.body rather than nesting here, so this doesn't
clip anything that needs to escape the frame. */
overflow: hidden;
}
#site-editor .interface-interface-skeleton {
position: relative !important;
top: auto !important;
left: auto !important;
right: auto !important;
bottom: auto !important;
background: transparent !important;
border-radius: 0 !important;
box-shadow: none !important;
padding-top: 0 !important;
overflow: visible !important;
width: 100%;
height: 100%;
}
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);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
margin: 16px var(--aurora-gutter-r) 24px 24px;
padding: 32px;
min-height: calc(100vh - var(--aurora-toolbar-h) - 40px);
/* Cap the card's own height to whatever's left below the toolbar and let
*it* scroll internally, instead of growing to fit tall native pages
(Comments, Plugins, Add User, Settings, Activity Log, Database
Explorer, ...) and forcing the whole document to scroll — the sidebar/
toolbar are fixed, so a tall #wpbody-content just meant a lot of empty
scroll distance below the fold with nothing visibly moving except the
content. Same fix as the taskbar-present case below, just unconditional. */
max-height: calc(100vh - var(--aurora-toolbar-h) - 40px);
overflow-y: auto;
/* Chrome's scroll anchoring tries to keep whatever's in view visually
stable when content shifts above it. Several native pages (Add Plugins'
plugin-card grid, most visibly) render their real content via JS well
after the initial paint, inserting it above stuff that was already
visible in this now-scrollable box — anchoring then "corrects" by
jumping scrollTop down to compensate, landing the page scrolled to
the middle/bottom on load instead of the top. Opting this container
out of anchoring is the standard fix for that class of bug. */
overflow-anchor: none;
box-sizing: border-box;
/* WP core sets #wpbody-content { float: left; width: 100% }, which (with
box-sizing left alone) ignores the margin above and overflows past the
right edge by margin-left + margin-right. Force it back to shrink-to-fit
so the margin is actually respected. */
float: none;
width: auto;
}
/* Gutenberg renders in its own fixed skeleton. The regular #wpbody-content
wrapper still exists on post-new.php/post.php, but it is inert; if framed
like normal native pages, it appears as a stray empty pill above the editor. */
html.aurora-ready body.block-editor-page #wpbody-content,
html.aurora-ready body.post-new-php #wpbody-content,
html.aurora-ready body.post-php #wpbody-content {
background: transparent !important;
border: 0 !important;
border-radius: 0 !important;
box-shadow: none !important;
margin: 0 !important;
min-height: 0 !important;
padding: 0 !important;
}
html.aurora-ready body.block-editor-page #wpbody-content > .aurora-winbar,
html.aurora-ready body.post-new-php #wpbody-content > .aurora-winbar,
html.aurora-ready body.post-php #wpbody-content > .aurora-winbar {
display: none !important;
}
/* SiteShell.vue's taskbar floats along the bottom edge (inset by
--aurora-sidebar-gap, same as the sidebar) only while a window is
minimized. A plain margin-bottom only guarantees a gap once the page is
scrolled all the way down — content taller than the viewport still
renders underneath the fixed taskbar on first paint, since a fixed
element doesn't reserve space from the rest of the page's flow. Instead,
cap the content box's own height to whatever's actually left between the
toolbar and the taskbar and let *it* scroll internally — the same way
the toolbar's reserved space at the top never lets content start behind
it, not just "eventually scroll clear of it". */
html.aurora-has-taskbar #wpbody-content,
html.aurora-has-taskbar .aurora-dashboard-frame {
/* #wpbody-content's base rule sets min-height: calc(100vh - toolbar-h -
40px) for the normal (no-taskbar) case — per spec, when min-height is
larger than max-height, min-height always wins and max-height is
silently ignored. Without this override the box kept sizing to that
taller min-height regardless of the taskbar, which is why the
max-height below appeared to do nothing. */
min-height: 0;
max-height: calc(
100vh - var(--aurora-toolbar-h) - 16px - 24px - var(--aurora-taskbar-h) -
var(--aurora-sidebar-gap) * 2
);
overflow-y: auto;
overflow-anchor: none;
}
/* The block editor's skeleton is already positioned with fixed insets
(top/left/right/bottom) rather than margin, so reserving taskbar space
is just moving its bottom inset in — no max-height/overflow trick
needed there, unlike the margin-based elements above. */
html.aurora-has-taskbar .interface-interface-skeleton,
html.aurora-has-taskbar #site-editor {
bottom: calc(24px + var(--aurora-taskbar-h) + var(--aurora-sidebar-gap) * 2) !important;
}
/* 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__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. */
.aurora-dashboard-frame {
background: var(--aurora-frame-bg);
border: 1px solid var(--aurora-frame-border);
border-radius: var(--aurora-radius-lg);
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
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
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
here instead. */
#aurora-admin-dashboard-notices:empty {
display: none;
}
#aurora-admin-dashboard-notices .notice {
background: var(--aurora-card-bg);
color: var(--aurora-text);
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,
not the full viewport, so painting var(--aurora-app-bg) on it computes
its own independent (and visibly mismatched) gradient instance instead
of sharing the one fixed gradient plane painted on html/body. */
html.aurora-ready body.toplevel_page_aurora-admin #wpbody-content {
border: none;
border-radius: 0;
box-shadow: none;
}
/*
* Native WordPress pages are fully dark-themed by a dedicated stylesheet
* (admin/assets/native-dark.css), enqueued only on native pages and gated
* on dark mode. It restyles WP's postboxes, forms, tables, buttons, etc.
* Keeping that large surface in one isolated, native-only file means it
* can never leak onto Aurora's own pages or affect light mode.
*/