Add theme presets, gradient backgrounds, and macOS-style window chrome

Replaces the old light/dark toggle with 10 fixed color themes (plus
Black & Grey and White) that drive a coordinated gradient palette across
the whole admin UI, a Google Fonts picker, and a native-page dark-mode
stylesheet that now covers modals and plugin/theme card grids. Fixes
several background/gradient seams where the sidebar, toolbar, and content
frame were each painting their own independent copy of the page gradient
instead of sharing one continuous plane.

Also adds a macOS-style traffic-light title bar to every page (close,
minimize, maximize) and a persistent bottom taskbar so a minimized page
can be restored from anywhere, plus a Plugins management page.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
nixpanel
2026-07-03 11:49:15 -05:00
co-authored by Claude Sonnet 5
parent db07e21f9e
commit 4a547d2c50
26 changed files with 1816 additions and 223 deletions
+16 -21
View File
@@ -19,10 +19,6 @@ const props = defineProps({
type: String,
default: '',
},
isDark: {
type: Boolean,
default: false,
},
collapsed: {
type: Boolean,
default: false,
@@ -35,19 +31,13 @@ const props = defineProps({
type: Object,
required: true,
},
theme: {
type: String,
default: 'system',
},
});
const emit = defineEmits(['set-theme']);
// Custom logo from Settings > General. Dark mode prefers the dark variant
// and falls back to the standard logo; no logo set = "Aurora" wordmark.
const activeLogo = computed(() =>
props.isDark ? props.darkLogo || props.logo : props.logo
);
// Custom logo from Settings > General. Every theme preset is a dark-toned
// palette now (no separate light mode), so the dark-variant logo is always
// preferred when set; falls back to the standard logo, or the "Aurora"
// wordmark if neither is set.
const activeLogo = computed(() => props.darkLogo || props.logo);
// Normalize any admin URL down to the part after /wp-admin/ so we can
// compare the current page against menu targets regardless of host/scheme.
@@ -209,8 +199,6 @@ const isAuroraActive = (item) => normalize(item.url) === current.value;
<UserMenu
:server-data="serverData"
:collapsed="collapsed"
:theme="theme"
@set-theme="(t) => emit('set-theme', t)"
/>
</nav>
</template>
@@ -218,11 +206,18 @@ const isAuroraActive = (item) => normalize(item.url) === current.value;
<style scoped>
.sidebar {
position: fixed;
top: 0;
left: 0;
top: var(--aurora-sidebar-gap);
left: var(--aurora-sidebar-gap);
bottom: var(--aurora-sidebar-gap);
width: var(--aurora-sidebar-w);
height: 100vh;
background: var(--aurora-app-bg);
height: auto;
/* Same surface treatment as the dashboard cards (AuroraCard.vue) —
solid card background + rounded corners, floating over the page
gradient with a gap on every side now that it's inset instead of
flush against the viewport edges. */
background: var(--aurora-card-bg);
border: 1px solid var(--aurora-card-border);
border-radius: 20px;
transition: width 0.2s ease;
z-index: 99999;
box-sizing: border-box;
+3 -2
View File
@@ -129,10 +129,11 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
.toolbar {
position: fixed;
top: 0;
left: var(--aurora-sidebar-w);
left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2);
right: 0;
height: var(--aurora-toolbar-h);
background: var(--aurora-app-bg);
/* No background — see Sidebar.vue; the fixed html/body gradient shows
through so the whole shell reads as one continuous background. */
display: flex;
align-items: center;
justify-content: space-between;
-88
View File
@@ -4,11 +4,8 @@ import { ref, computed, onMounted, onUnmounted } from 'vue';
const props = defineProps({
serverData: { type: Object, required: true },
collapsed: { type: Boolean, default: false },
theme: { type: String, default: 'system' }, // 'light' | 'dark' | 'system'
});
const emit = defineEmits(['set-theme']);
const open = ref(false);
const root = ref(null);
@@ -53,36 +50,6 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
Sign Out
</a>
</div>
<div class="user-menu__theme">
<span class="user-menu__theme-label">Theme</span>
<div class="user-menu__segmented">
<button
type="button"
:class="{ 'is-active': theme === 'light' }"
title="Light"
@click="emit('set-theme', 'light')"
>
<span class="user-menu__swatch user-menu__swatch--light" />
</button>
<button
type="button"
:class="{ 'is-active': theme === 'dark' }"
title="Dark"
@click="emit('set-theme', 'dark')"
>
<span class="user-menu__swatch user-menu__swatch--dark" />
</button>
<button
type="button"
:class="{ 'is-active': theme === 'system' }"
title="Match system"
@click="emit('set-theme', 'system')"
>
<span class="user-menu__swatch user-menu__swatch--system" />
</button>
</div>
</div>
</div>
<button
@@ -224,59 +191,4 @@ onUnmounted(() => document.removeEventListener('click', onDocClick));
color: #ef4444;
}
.user-menu__theme {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
}
.user-menu__theme-label {
font-size: 0.8125rem;
color: var(--aurora-text-muted);
}
.user-menu__segmented {
display: flex;
gap: 2px;
background: var(--aurora-bg-subtle);
border-radius: 8px;
padding: 2px;
}
.user-menu__segmented button {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: none;
background: none;
border-radius: 6px;
cursor: pointer;
padding: 3px;
}
.user-menu__segmented button.is-active {
background: var(--aurora-bg);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.user-menu__swatch {
display: block;
width: 100%;
height: 100%;
border-radius: 4px;
border: 1px solid rgba(127, 127, 127, 0.35);
box-sizing: border-box;
}
.user-menu__swatch--light {
background: #ffffff;
}
.user-menu__swatch--dark {
background: #18181b;
}
.user-menu__swatch--system {
background: linear-gradient(135deg, #ffffff 0%, #ffffff 50%, #18181b 50%, #18181b 100%);
}
.user-menu__segmented button.is-active .user-menu__swatch {
border-color: var(--aurora-accent);
box-shadow: 0 0 0 1px var(--aurora-accent);
}
</style>