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]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
dc2a4435c5
commit
53ca6f62b9
@@ -31,7 +31,7 @@ defineProps({
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* Deeper than the generic --aurora-card-bg — the Dashboard is now
|
/* Deeper than the generic --aurora-card-bg — the Dashboard is now
|
||||||
wrapped in its own frame (windowChrome.js's .aurora-dashboard-frame,
|
wrapped in its own frame (dashboardFrame.js's .aurora-dashboard-frame,
|
||||||
using --aurora-frame-bg), and that's close in tone to --aurora-card-bg
|
using --aurora-frame-bg), and that's close in tone to --aurora-card-bg
|
||||||
for most presets, so cards would nearly disappear into it otherwise. */
|
for most presets, so cards would nearly disappear into it otherwise. */
|
||||||
background: var(--aurora-card-bg-deep, var(--aurora-card-bg));
|
background: var(--aurora-card-bg-deep, var(--aurora-card-bg));
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { ref, onMounted } from 'vue';
|
|||||||
import Sidebar from './components/Sidebar.vue';
|
import Sidebar from './components/Sidebar.vue';
|
||||||
import Toolbar from './components/Toolbar.vue';
|
import Toolbar from './components/Toolbar.vue';
|
||||||
import { applyThemePalette, applyFontFamily } from '@/pages/settings/applyLiveTheme.js';
|
import { applyThemePalette, applyFontFamily } from '@/pages/settings/applyLiveTheme.js';
|
||||||
import { initWindowChrome } from './windowChrome.js';
|
import { initDashboardFrame } from './dashboardFrame.js';
|
||||||
import { getMinimizedWindows, removeMinimizedWindow } from './taskbar.js';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
serverData: {
|
serverData: {
|
||||||
@@ -25,21 +24,7 @@ const toggleMenu = () => {
|
|||||||
localStorage.setItem('aurora-menu-collapsed', collapsed.value ? '1' : '0');
|
localStorage.setItem('aurora-menu-collapsed', collapsed.value ? '1' : '0');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Every minimized window (taskbar.js persists the list in sessionStorage
|
|
||||||
// across the page loads minimizing triggers). Rendered as taskbar items at
|
|
||||||
// the bottom of every page since SiteShell mounts on all of them — clicking
|
|
||||||
// one navigates back to it and removes just that entry.
|
|
||||||
const minimizedWindows = ref([]);
|
|
||||||
const restoreWindow = (win) => {
|
|
||||||
removeMinimizedWindow(win.id);
|
|
||||||
window.location.href = win.url;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
minimizedWindows.value = getMinimizedWindows();
|
|
||||||
// Reserve bottom space for the taskbar (shell-frame.css) so page content
|
|
||||||
// stops above it instead of running underneath.
|
|
||||||
document.documentElement.classList.toggle('aurora-has-taskbar', minimizedWindows.value.length > 0);
|
|
||||||
const settings = props.serverData?.settings || {};
|
const settings = props.serverData?.settings || {};
|
||||||
// Every theme preset is its own self-contained dark-toned palette now —
|
// Every theme preset is its own self-contained dark-toned palette now —
|
||||||
// no separate light/dark mode, so this class is always on. It's kept
|
// no separate light/dark mode, so this class is always on. It's kept
|
||||||
@@ -49,7 +34,7 @@ onMounted(() => {
|
|||||||
applyThemePalette(settings.theme_preset || 'indigo');
|
applyThemePalette(settings.theme_preset || 'indigo');
|
||||||
applyCollapsed();
|
applyCollapsed();
|
||||||
applyFontFamily(settings.font_family);
|
applyFontFamily(settings.font_family);
|
||||||
initWindowChrome(props.serverData?.adminUrl);
|
initDashboardFrame();
|
||||||
// Signal the shell is live: reveals the framed content and commits to
|
// Signal the shell is live: reveals the framed content and commits to
|
||||||
// keeping native chrome hidden (the PHP failsafe stops watching once
|
// keeping native chrome hidden (the PHP failsafe stops watching once
|
||||||
// aurora-ready is present).
|
// aurora-ready is present).
|
||||||
@@ -73,74 +58,13 @@ onMounted(() => {
|
|||||||
:server-data="serverData"
|
:server-data="serverData"
|
||||||
@toggle-menu="toggleMenu"
|
@toggle-menu="toggleMenu"
|
||||||
/>
|
/>
|
||||||
<div v-if="minimizedWindows.length" class="aurora-taskbar">
|
|
||||||
<button
|
|
||||||
v-for="win in minimizedWindows"
|
|
||||||
:key="win.id"
|
|
||||||
type="button"
|
|
||||||
class="aurora-taskbar__item"
|
|
||||||
@click="restoreWindow(win)"
|
|
||||||
>
|
|
||||||
<span class="aurora-taskbar__dot" />
|
|
||||||
{{ win.title }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* Sidebar, Toolbar and the taskbar are all position:fixed, so this
|
/* Sidebar and Toolbar are both position:fixed, so this wrapper has no
|
||||||
wrapper has no layout role — it just groups them under one mounted
|
layout role — it just groups them under one mounted root. */
|
||||||
root. */
|
|
||||||
.site-shell {
|
.site-shell {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Full-width docked bar, but inset with the same gap the sidebar floats
|
|
||||||
with (not flush against the browser edges or the window above it) and
|
|
||||||
fully rounded + shadowed so it reads as its own separate surface rather
|
|
||||||
than an extension of the content frame it sits under. Page content
|
|
||||||
reserves space above it via html.aurora-has-taskbar in shell-frame.css. */
|
|
||||||
.aurora-taskbar {
|
|
||||||
position: fixed;
|
|
||||||
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2);
|
|
||||||
right: var(--aurora-sidebar-gap);
|
|
||||||
bottom: var(--aurora-sidebar-gap);
|
|
||||||
height: var(--aurora-taskbar-h);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 0 16px;
|
|
||||||
background: var(--aurora-card-bg);
|
|
||||||
border: 1px solid var(--aurora-card-border);
|
|
||||||
border-radius: var(--aurora-radius-lg);
|
|
||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 200001;
|
|
||||||
overflow-x: auto;
|
|
||||||
transition: left 0.2s ease;
|
|
||||||
}
|
|
||||||
.aurora-taskbar__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
background: var(--aurora-bg-subtle);
|
|
||||||
border: 1px solid var(--aurora-border);
|
|
||||||
border-radius: 999px;
|
|
||||||
padding: 8px 18px 8px 10px;
|
|
||||||
color: var(--aurora-text);
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.aurora-taskbar__item:hover {
|
|
||||||
border-color: var(--aurora-accent);
|
|
||||||
}
|
|
||||||
.aurora-taskbar__dot {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #febc2e;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
+11
-172
@@ -14,13 +14,6 @@
|
|||||||
:root {
|
:root {
|
||||||
--aurora-sidebar-w: 264px;
|
--aurora-sidebar-w: 264px;
|
||||||
--aurora-toolbar-h: 56px;
|
--aurora-toolbar-h: 56px;
|
||||||
/* SiteShell.vue's taskbar, shown only while a window is minimized
|
|
||||||
(html.aurora-has-taskbar toggles the bottom space reserved for it). */
|
|
||||||
--aurora-taskbar-h: 56px;
|
|
||||||
/* Height of the strip reserved at the top of the block editor's frame
|
|
||||||
for .aurora-winbar--editor's traffic-light dots (a sibling element,
|
|
||||||
not a child of the skeleton — see windowChrome.js). */
|
|
||||||
--aurora-editor-winbar-h: 44px;
|
|
||||||
/* Space between the sidebar card and the browser's left/top/bottom
|
/* Space between the sidebar card and the browser's left/top/bottom
|
||||||
edges (Sidebar.vue) — the toolbar and #wpcontent offsets below add
|
edges (Sidebar.vue) — the toolbar and #wpcontent offsets below add
|
||||||
the same amount so nothing overlaps the floating sidebar. */
|
the same amount so nothing overlaps the floating sidebar. */
|
||||||
@@ -170,12 +163,6 @@ html.aurora-ready #site-editor {
|
|||||||
border-radius: var(--aurora-radius-lg);
|
border-radius: var(--aurora-radius-lg);
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
transition: left 0.2s ease;
|
transition: left 0.2s ease;
|
||||||
/* Reserves a strip at the top for .aurora-winbar--editor's dots (a
|
|
||||||
sibling, not a child — see windowChrome.js) so they sit in their own
|
|
||||||
clear space instead of overlapping the editor's own logo/toolbar row.
|
|
||||||
border-box so the padding comes out of the top/left/right/bottom
|
|
||||||
inset box already defined above, rather than adding to it. */
|
|
||||||
padding-top: var(--aurora-editor-winbar-h);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
/* border-radius alone doesn't clip children — Gutenberg's own white
|
/* border-radius alone doesn't clip children — Gutenberg's own white
|
||||||
canvas background ran straight past the rounded bottom corners as a
|
canvas background ran straight past the rounded bottom corners as a
|
||||||
@@ -250,48 +237,6 @@ html.aurora-ready body.post-php #wpbody-content {
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.aurora-ready body.block-editor-page #wpbody-content > .aurora-winbar,
|
|
||||||
html.aurora-ready body.post-new-php #wpbody-content > .aurora-winbar,
|
|
||||||
html.aurora-ready body.post-php #wpbody-content > .aurora-winbar {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SiteShell.vue's taskbar floats along the bottom edge (inset by
|
|
||||||
--aurora-sidebar-gap, same as the sidebar) only while a window is
|
|
||||||
minimized. A plain margin-bottom only guarantees a gap once the page is
|
|
||||||
scrolled all the way down — content taller than the viewport still
|
|
||||||
renders underneath the fixed taskbar on first paint, since a fixed
|
|
||||||
element doesn't reserve space from the rest of the page's flow. Instead,
|
|
||||||
cap the content box's own height to whatever's actually left between the
|
|
||||||
toolbar and the taskbar and let *it* scroll internally — the same way
|
|
||||||
the toolbar's reserved space at the top never lets content start behind
|
|
||||||
it, not just "eventually scroll clear of it". */
|
|
||||||
html.aurora-has-taskbar #wpbody-content,
|
|
||||||
html.aurora-has-taskbar .aurora-dashboard-frame {
|
|
||||||
/* #wpbody-content's base rule sets min-height: calc(100vh - toolbar-h -
|
|
||||||
40px) for the normal (no-taskbar) case — per spec, when min-height is
|
|
||||||
larger than max-height, min-height always wins and max-height is
|
|
||||||
silently ignored. Without this override the box kept sizing to that
|
|
||||||
taller min-height regardless of the taskbar, which is why the
|
|
||||||
max-height below appeared to do nothing. */
|
|
||||||
min-height: 0;
|
|
||||||
max-height: calc(
|
|
||||||
100vh - var(--aurora-toolbar-h) - 16px - 24px - var(--aurora-taskbar-h) -
|
|
||||||
var(--aurora-sidebar-gap) * 2
|
|
||||||
);
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-anchor: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The block editor's skeleton is already positioned with fixed insets
|
|
||||||
(top/left/right/bottom) rather than margin, so reserving taskbar space
|
|
||||||
is just moving its bottom inset in — no max-height/overflow trick
|
|
||||||
needed there, unlike the margin-based elements above. */
|
|
||||||
html.aurora-has-taskbar .interface-interface-skeleton,
|
|
||||||
html.aurora-has-taskbar #site-editor {
|
|
||||||
bottom: calc(24px + var(--aurora-taskbar-h) + var(--aurora-sidebar-gap) * 2) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Theme installer preview ("Add Themes" > click a theme > full "Preview &
|
/* Theme installer preview ("Add Themes" > click a theme > full "Preview &
|
||||||
Install" overlay, theme-install.php). WP core's own .wp-full-overlay
|
Install" overlay, theme-install.php). WP core's own .wp-full-overlay
|
||||||
component (shared with the Customizer, but only .theme-install-overlay
|
component (shared with the Customizer, but only .theme-install-overlay
|
||||||
@@ -355,86 +300,21 @@ html.aurora-ready .theme-install-overlay.collapsed {
|
|||||||
|
|
||||||
html.aurora-ready .theme-install-overlay .wp-full-overlay-sidebar {
|
html.aurora-ready .theme-install-overlay .wp-full-overlay-sidebar {
|
||||||
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important;
|
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important;
|
||||||
top: calc(var(--aurora-toolbar-h) + 16px + var(--aurora-editor-winbar-h)) !important;
|
top: calc(var(--aurora-toolbar-h) + 16px) !important;
|
||||||
bottom: 24px !important;
|
bottom: 24px !important;
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
border-top-left-radius: var(--aurora-radius-lg);
|
border-top-left-radius: var(--aurora-radius-lg);
|
||||||
}
|
}
|
||||||
html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
|
html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
|
||||||
top: var(--aurora-editor-winbar-h) !important;
|
top: 0 !important;
|
||||||
border-top-right-radius: var(--aurora-radius-lg);
|
border-top-right-radius: var(--aurora-radius-lg);
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* macOS-style title bar (windowChrome.js). Most pages get it injected as
|
|
||||||
the first child of #wpbody-content — negative margins cancel the 32px
|
|
||||||
padding above so it spans edge-to-edge like a real window title bar. */
|
|
||||||
.aurora-winbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.aurora-winbar--editor {
|
|
||||||
position: fixed;
|
|
||||||
/* Centered vertically within the skeleton's reserved top strip
|
|
||||||
(--aurora-editor-winbar-h), inset from its left edge to line up with
|
|
||||||
the padding every other title bar uses. */
|
|
||||||
top: calc(
|
|
||||||
var(--aurora-toolbar-h) + 16px + (var(--aurora-editor-winbar-h) - 12px) / 2
|
|
||||||
);
|
|
||||||
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px + 20px);
|
|
||||||
height: 12px;
|
|
||||||
padding: 0;
|
|
||||||
background: transparent;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
z-index: 100000;
|
|
||||||
transition: left 0.2s ease;
|
|
||||||
}
|
|
||||||
#wpbody-content > .aurora-winbar {
|
|
||||||
margin: -32px -32px 20px -32px;
|
|
||||||
padding: 14px 16px;
|
|
||||||
border-bottom: 1px solid var(--aurora-frame-border);
|
|
||||||
border-top-left-radius: var(--aurora-radius-lg);
|
|
||||||
border-top-right-radius: var(--aurora-radius-lg);
|
|
||||||
}
|
|
||||||
.aurora-winbar__crumb {
|
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--aurora-text-muted);
|
|
||||||
text-decoration: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.aurora-winbar__crumb:hover {
|
|
||||||
color: var(--aurora-text);
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot:hover {
|
|
||||||
filter: brightness(1.15);
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot--close {
|
|
||||||
background: #ff5f57;
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot--minimize {
|
|
||||||
background: #febc2e;
|
|
||||||
}
|
|
||||||
.aurora-winbar__dot--maximize {
|
|
||||||
background: #28c840;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Dashboard bypasses #wpbody-content (DashboardTakeover.php renders
|
/* The Dashboard bypasses #wpbody-content (DashboardTakeover.php renders
|
||||||
it into a separate sibling — see windowChrome.js), so it never got the
|
it into a separate sibling — see dashboardFrame.js), so it never got the
|
||||||
card frame every other page has. windowChrome.js wraps the bar + the
|
card frame every other page has. dashboardFrame.js wraps the dashboard's
|
||||||
dashboard's mount point in this div to give it the same treatment. */
|
mount point in this div to give it the same treatment. */
|
||||||
.aurora-dashboard-frame {
|
.aurora-dashboard-frame {
|
||||||
background: var(--aurora-frame-bg);
|
background: var(--aurora-frame-bg);
|
||||||
border: 1px solid var(--aurora-frame-border);
|
border: 1px solid var(--aurora-frame-border);
|
||||||
@@ -444,25 +324,19 @@ html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
/* Same unconditional height cap as #wpbody-content's base rule — this
|
/* Same unconditional height cap as #wpbody-content's base rule — this
|
||||||
element never got it, since the Dashboard bypasses #wpbody-content
|
element never got it, since the Dashboard bypasses #wpbody-content
|
||||||
entirely (a separate sibling — see windowChrome.js) and only had the
|
entirely (a separate sibling — see dashboardFrame.js). Once html/body
|
||||||
taskbar-present variant below. Once html/body were locked to
|
were locked to overflow:hidden (to kill a phantom document-level
|
||||||
overflow:hidden (to kill a phantom document-level scrollbar on
|
scrollbar on another page), the dashboard's content past the first
|
||||||
another page), the dashboard's content past the first ~1500px became
|
~1500px became completely unreachable: no internal scroll here, and
|
||||||
completely unreachable: no internal scroll here, and no document
|
no document
|
||||||
scroll left to fall back on either. */
|
scroll left to fall back on either. */
|
||||||
max-height: calc(100vh - var(--aurora-toolbar-h) - 40px);
|
max-height: calc(100vh - var(--aurora-toolbar-h) - 40px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-anchor: none;
|
overflow-anchor: none;
|
||||||
}
|
}
|
||||||
.aurora-dashboard-frame > .aurora-winbar {
|
|
||||||
padding: 14px 20px;
|
|
||||||
border-bottom: 1px solid var(--aurora-frame-border);
|
|
||||||
border-top-left-radius: var(--aurora-radius-lg);
|
|
||||||
border-top-right-radius: var(--aurora-radius-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Custom admin notices (Notices::render_for_dashboard(), reparented in
|
/* Custom admin notices (Notices::render_for_dashboard(), reparented in
|
||||||
here by windowChrome.js) — native-dark.css already themes .notice
|
here by dashboardFrame.js) — native-dark.css already themes .notice
|
||||||
elsewhere via #wpbody-content, but that stylesheet isn't loaded on the
|
elsewhere via #wpbody-content, but that stylesheet isn't loaded on the
|
||||||
Dashboard at all (Shell::is_own_page() treats index.php as one of
|
Dashboard at all (Shell::is_own_page() treats index.php as one of
|
||||||
Aurora's own pages), so it needs its own copy of the same treatment
|
Aurora's own pages), so it needs its own copy of the same treatment
|
||||||
@@ -476,41 +350,6 @@ html.aurora-ready .theme-install-overlay .wp-full-overlay-main {
|
|||||||
margin: 16px 20px 0;
|
margin: 16px 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Yellow dot: on the Dashboard itself there's nowhere further "home" to
|
|
||||||
send it, so minimize just collapses the frame down to the title bar in
|
|
||||||
place — everywhere else, minimize navigates to the dashboard instead
|
|
||||||
(see windowChrome.js) and SiteShell.vue's taskbar offers a way back. */
|
|
||||||
html.aurora-minimized #aurora-admin-dashboard-root {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Green dot: hide Aurora's own chrome (sidebar/toolbar) and let the
|
|
||||||
content reclaim the full browser window, like restoring a real OS
|
|
||||||
window to fullscreen. */
|
|
||||||
html.aurora-maximized .sidebar,
|
|
||||||
html.aurora-maximized .toolbar {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
html.aurora-ready.aurora-maximized #wpcontent {
|
|
||||||
margin-left: 0 !important;
|
|
||||||
}
|
|
||||||
html.aurora-ready.aurora-maximized .interface-interface-skeleton,
|
|
||||||
html.aurora-ready.aurora-maximized #site-editor {
|
|
||||||
top: 0 !important;
|
|
||||||
left: 0 !important;
|
|
||||||
right: 0 !important;
|
|
||||||
bottom: 0 !important;
|
|
||||||
height: auto !important;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
html.aurora-maximized .aurora-winbar--editor {
|
|
||||||
top: calc((var(--aurora-editor-winbar-h) - 12px) / 2);
|
|
||||||
left: 20px;
|
|
||||||
}
|
|
||||||
html.aurora-maximized .aurora-taskbar {
|
|
||||||
left: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The settings page renders its own two boxed panels, so drop the outer
|
/* The settings page renders its own two boxed panels, so drop the outer
|
||||||
content frame there — leaving just those panels on the dark backdrop.
|
content frame there — leaving just those panels on the dark backdrop.
|
||||||
No background here: #wpbody-content is inset from the sidebar/gutter,
|
No background here: #wpbody-content is inset from the sidebar/gutter,
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* Tracks every "minimized" window across page loads. Aurora is a normal
|
|
||||||
* multi-page WP admin (each nav is a full page load), so a real taskbar
|
|
||||||
* needs to survive navigation — sessionStorage (tab-scoped, clears when the
|
|
||||||
* tab closes) is enough for that. Stored as a list, not a single slot —
|
|
||||||
* minimizing a second page used to silently overwrite the first one's
|
|
||||||
* entry, so only the most recent minimize ever showed up in the taskbar.
|
|
||||||
*/
|
|
||||||
const STORAGE_KEY = 'aurora-minimized-windows';
|
|
||||||
|
|
||||||
export function getMinimizedWindows() {
|
|
||||||
try {
|
|
||||||
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
||||||
const parsed = raw ? JSON.parse(raw) : [];
|
|
||||||
return Array.isArray(parsed) ? parsed : [];
|
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveMinimizedWindows(list) {
|
|
||||||
try {
|
|
||||||
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(list));
|
|
||||||
} catch {
|
|
||||||
/* sessionStorage unavailable (e.g. private mode) — minimize just won't persist */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds (or, if the same page is already minimized, replaces) an entry. */
|
|
||||||
export function addMinimizedWindow(title, url) {
|
|
||||||
const list = getMinimizedWindows().filter((w) => w.url !== url);
|
|
||||||
list.push({ id: `${Date.now()}-${Math.random().toString(36).slice(2)}`, title, url });
|
|
||||||
saveMinimizedWindows(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeMinimizedWindow(id) {
|
|
||||||
saveMinimizedWindows(getMinimizedWindows().filter((w) => w.id !== id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Best-effort readable label for the current page, used as the taskbar
|
|
||||||
* item's title. Prefers the page's own on-screen <h1> over document.title —
|
|
||||||
* WordPress's title-tag lookup walks the $submenu global to find a page's
|
|
||||||
* title, which comes up empty for Aurora's sub-app pages (SubApps.php
|
|
||||||
* registers each one normally, then immediately remove_submenu_page()s it
|
|
||||||
* to keep it out of the native menu — that breaks WP's own title lookup,
|
|
||||||
* not just this). document.title is still the fallback for pages where
|
|
||||||
* that isn't an issue (Settings, native WP pages, the Dashboard).
|
|
||||||
*/
|
|
||||||
export function currentPageTitle() {
|
|
||||||
const heading = document.querySelector('#wpbody-content h1, #aurora-admin-dashboard-root h1');
|
|
||||||
if (heading && heading.textContent.trim()) {
|
|
||||||
return heading.textContent.trim();
|
|
||||||
}
|
|
||||||
const raw = document.title || '';
|
|
||||||
return raw.split('‹')[0].trim() || 'Window';
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
/**
|
|
||||||
* Adds a macOS-style traffic-light title bar to the top of the page content.
|
|
||||||
* Three cases, in priority order:
|
|
||||||
* 1. The Dashboard — DashboardTakeover.php renders it into a separate
|
|
||||||
* #aurora-admin-dashboard-root sibling, above #wpbody (which it hides),
|
|
||||||
* to fully replace the native dashboard. Gets wrapped in a new
|
|
||||||
* .aurora-dashboard-frame div to match the card treatment
|
|
||||||
* #wpbody-content already has everywhere else.
|
|
||||||
* 2. The block editor — gets only the traffic-light controls, overlaid on
|
|
||||||
* the editor frame without a full-width titlebar surface.
|
|
||||||
* 3. Everything else — native WP pages and all of Aurora's own Vue pages,
|
|
||||||
* since each mounts its root div inside #wpbody-content. The bar is
|
|
||||||
* inserted as its first child.
|
|
||||||
*
|
|
||||||
* Red closes (navigates back to the Aurora dashboard). Yellow minimizes —
|
|
||||||
* on any page other than the dashboard, that means "save where I am and
|
|
||||||
* send me home", with SiteShell.vue's taskbar offering a way back; on the
|
|
||||||
* dashboard itself (already home) it just collapses in place instead,
|
|
||||||
* since there's nowhere further back to send it. Green hides Aurora's own
|
|
||||||
* sidebar/toolbar so the content fills the browser window. Minimized pages
|
|
||||||
* are tracked as a list (taskbar.js), not a single slot, so minimizing
|
|
||||||
* more than one shows up as separate taskbar items rather than the latest
|
|
||||||
* silently replacing the previous one.
|
|
||||||
*/
|
|
||||||
import { addMinimizedWindow, currentPageTitle } from './taskbar.js';
|
|
||||||
|
|
||||||
function buildBar(adminUrl, isDashboard) {
|
|
||||||
const bar = document.createElement('div');
|
|
||||||
bar.className = 'aurora-winbar';
|
|
||||||
|
|
||||||
const makeDot = (variant, label, onClick) => {
|
|
||||||
const dot = document.createElement('button');
|
|
||||||
dot.type = 'button';
|
|
||||||
dot.className = 'aurora-winbar__dot aurora-winbar__dot--' + variant;
|
|
||||||
dot.setAttribute('aria-label', label);
|
|
||||||
dot.title = label;
|
|
||||||
dot.addEventListener('click', onClick);
|
|
||||||
return dot;
|
|
||||||
};
|
|
||||||
|
|
||||||
const root = document.documentElement;
|
|
||||||
|
|
||||||
bar.appendChild(
|
|
||||||
makeDot('close', 'Close', () => {
|
|
||||||
window.location.href = adminUrl || '/wp-admin/';
|
|
||||||
})
|
|
||||||
);
|
|
||||||
bar.appendChild(
|
|
||||||
makeDot('minimize', 'Minimize', () => {
|
|
||||||
if (isDashboard) {
|
|
||||||
root.classList.toggle('aurora-minimized');
|
|
||||||
root.classList.remove('aurora-maximized');
|
|
||||||
} else {
|
|
||||||
addMinimizedWindow(currentPageTitle(), window.location.href);
|
|
||||||
window.location.href = adminUrl || '/wp-admin/';
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
bar.appendChild(
|
|
||||||
makeDot('maximize', 'Maximize', () => {
|
|
||||||
root.classList.toggle('aurora-maximized');
|
|
||||||
root.classList.remove('aurora-minimized');
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBlockEditorPage() {
|
|
||||||
const path = window.location.pathname;
|
|
||||||
return (
|
|
||||||
document.body.classList.contains('block-editor-page') ||
|
|
||||||
path.endsWith('/post-new.php') ||
|
|
||||||
path.endsWith('/post.php')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WP core adds a "post-type-{slug}" class to <body> on every post edit
|
|
||||||
// screen — the same signal used here to build a "back to the list" link,
|
|
||||||
// since Posts ("edit.php") and Pages ("edit.php?post_type=page") are now
|
|
||||||
// hijacked in place at their native URLs (see HijackedNativePages.php) and
|
|
||||||
// there's no single admin.php?page=... URL to hardcode anymore.
|
|
||||||
//
|
|
||||||
// The Site Editor (site-editor.php) also carries the "block-editor-page"
|
|
||||||
// body class isBlockEditorPage() matches on, but has no "post-type-*"
|
|
||||||
// class (it edits templates/template parts, not a post) — returning null
|
|
||||||
// here rather than guessing "Posts" is what keeps the crumb from showing
|
|
||||||
// up somewhere it doesn't make sense.
|
|
||||||
function editorBackLink(adminUrl) {
|
|
||||||
const match = [...document.body.classList].find((c) => c.startsWith('post-type-'));
|
|
||||||
if (!match) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const postType = match.replace('post-type-', '');
|
|
||||||
const base = adminUrl || '/wp-admin/';
|
|
||||||
if (postType === 'post') {
|
|
||||||
return { label: 'Posts', href: base + 'edit.php' };
|
|
||||||
}
|
|
||||||
if (postType === 'page') {
|
|
||||||
return { label: 'Pages', href: base + 'edit.php?post_type=page' };
|
|
||||||
}
|
|
||||||
return { label: postType, href: base + 'edit.php?post_type=' + encodeURIComponent(postType) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// theme-install.php's "Preview & Install" overlay (WP core's
|
|
||||||
// .wp-full-overlay component) needs a permanently-running observer, not a
|
|
||||||
// one-shot check, for two reasons: (1) core's own Backbone view creates it
|
|
||||||
// lazily the first time a theme is clicked, so it's missing from the
|
|
||||||
// initial DOM at initWindowChrome()'s call time; (2) every subsequent
|
|
||||||
// theme selection re-renders the overlay's contents from scratch (its own
|
|
||||||
// view.render() replaces all children to show the newly-selected theme's
|
|
||||||
// details), wiping out anything inserted into it — confirmed live: the bar
|
|
||||||
// was there after the very first click, gone after picking a second theme.
|
|
||||||
// Kept running for the page's whole lifetime rather than disconnecting
|
|
||||||
// after the first successful insert. Independent of the rest of this
|
|
||||||
// file's dedupe guard (a normal page winbar already exists in
|
|
||||||
// #wpbody-content here too; this is a second, additional bar for the
|
|
||||||
// overlay specifically, not a replacement for it).
|
|
||||||
function watchForThemeOverlay(adminUrl) {
|
|
||||||
const ensureInserted = () => {
|
|
||||||
const overlay = document.querySelector('.theme-install-overlay');
|
|
||||||
if (overlay && !overlay.querySelector('.aurora-winbar')) {
|
|
||||||
const bar = buildBar(adminUrl, false);
|
|
||||||
bar.classList.add('aurora-winbar--editor');
|
|
||||||
overlay.insertBefore(bar, overlay.firstChild);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ensureInserted();
|
|
||||||
new MutationObserver(ensureInserted).observe(document.body, { childList: true, subtree: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initWindowChrome(adminUrl) {
|
|
||||||
if (document.body.classList.contains('theme-install-php')) {
|
|
||||||
watchForThemeOverlay(adminUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.querySelector('.aurora-winbar')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dashboardRoot = document.getElementById('aurora-admin-dashboard-root');
|
|
||||||
if (dashboardRoot) {
|
|
||||||
const bar = buildBar(adminUrl, true);
|
|
||||||
const frame = document.createElement('div');
|
|
||||||
frame.className = 'aurora-dashboard-frame';
|
|
||||||
dashboardRoot.parentNode.insertBefore(frame, dashboardRoot);
|
|
||||||
frame.appendChild(bar);
|
|
||||||
// Custom admin notices (Notices::render_for_dashboard(), printed as a
|
|
||||||
// sibling right before the mount point) — reparented into the frame
|
|
||||||
// here too, so they render as part of the dashboard's own card
|
|
||||||
// instead of sitting outside it unstyled. Normally these reach the
|
|
||||||
// user via the plain admin_notices hook, but that renders inside
|
|
||||||
// #wpbody, which the Dashboard hides entirely to hide the *native*
|
|
||||||
// dashboard widgets — this is the replacement path for that one page.
|
|
||||||
const notices = document.getElementById('aurora-admin-dashboard-notices');
|
|
||||||
if (notices) frame.appendChild(notices);
|
|
||||||
frame.appendChild(dashboardRoot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBlockEditorPage()) {
|
|
||||||
const bar = buildBar(adminUrl, false);
|
|
||||||
bar.classList.add('aurora-winbar--editor');
|
|
||||||
|
|
||||||
const back = editorBackLink(adminUrl);
|
|
||||||
if (back) {
|
|
||||||
const crumb = document.createElement('a');
|
|
||||||
crumb.className = 'aurora-winbar__crumb';
|
|
||||||
crumb.href = back.href;
|
|
||||||
crumb.textContent = '← ' + back.label;
|
|
||||||
bar.appendChild(crumb);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.appendChild(bar);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wpbodyContent = document.getElementById('wpbody-content');
|
|
||||||
if (wpbodyContent) {
|
|
||||||
const bar = buildBar(adminUrl, false);
|
|
||||||
wpbodyContent.insertBefore(bar, wpbodyContent.firstChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user