PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
← All changes | includes/admin-bar.php +151 -181 0.8.81.1.10 View file →
@@ -1,32 +1,30 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode admin-bar toggle.
3 + * OpenStation admin-bar toggle.
4 4 *
5 - * Adds the "Switch to Desktop Mode" button to the admin bar's top-right
6 - * area and wires its click handler to the save-desktop-mode AJAX endpoint.
5 + * Adds the "Switch to OpenStation" button to the admin bar's top-right
6 + * area and wires its click handler to the save-openstation AJAX endpoint.
7 7 *
8 - * @package WPDesktopMode
8 + * @package OpenStation
9 9 */
10 10
11 11 defined( 'ABSPATH' ) || exit;
12 12
13 13 /**
14 - * Adds the desktop mode toggle to the admin bar.
14 + * Adds the OpenStation toggle to the admin bar.
15 15 *
16 - * Allows users to switch between classic admin and desktop mode,
16 + * Allows users to switch between classic admin and OpenStation,
17 17 * which renders admin screens in draggable, resizable windows.
18 18 *
19 - * @since 0.1.0
20 - *
21 19 * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance.
22 20 */
23 -function desktop_mode_admin_bar_toggle( $wp_admin_bar ) {
21 +function openstation_admin_bar_toggle( $wp_admin_bar ) {
24 22 if ( ! is_admin() || ! is_user_logged_in() ) {
25 23 return;
26 24 }
27 25
28 - // "Active" means "the user is *currently viewing* desktop mode",
26 + // "Active" means "the user is *currently viewing* OpenStation",
29 27 // not "the preference is enabled in user meta." These diverge on
30 28 // requests carrying the per-request classic override
31 29 // (`?desktop_mode_classic=1`) — the user's meta may be '1' but the
32 30 // page they're looking at right now is classic admin. If we went
@@ -31,25 +29,25 @@
31 29 // (`?desktop_mode_classic=1`) — the user's meta may be '1' but the
32 30 // page they're looking at right now is classic admin. If we went
33 31 // by meta alone, the toggle here would read "Switch to Classic
34 32 // Admin" on a page that's already classic, and the user's first
35 - // click would disable desktop mode entirely (redirecting to
33 + // click would disable OpenStation entirely (redirecting to
36 34 // classic admin) instead of taking them back into the shell.
37 35 // The second click would then re-enable it — a two-click trap.
38 - $is_active = desktop_mode_is_enabled() && ! desktop_mode_is_classic_request();
36 + $is_active = openstation_is_enabled() && ! openstation_is_classic_request();
39 37 $label = $is_active
40 38 ? __( 'Switch to Classic Admin', 'desktop-mode' )
41 - : __( 'Switch to Desktop Mode', 'desktop-mode' );
39 + : __( 'Switch to OpenStation', 'desktop-mode' );
42 40
43 41 $wp_admin_bar->add_node(
44 42 array(
45 43 'parent' => 'top-secondary',
46 - 'id' => 'desktop-mode-toggle',
44 + 'id' => 'os-toggle',
47 45 'title' => '<span class="ab-icon dashicons dashicons-desktop" aria-hidden="true"></span>'
48 46 . '<span class="ab-label">' . $label . '</span>',
49 47 'href' => '#',
50 48 'meta' => array(
51 - 'class' => $is_active ? 'desktop-mode-active' : '',
49 + 'class' => $is_active ? 'os-active' : '',
52 50 'tabindex' => 0,
53 51 'title' => $label,
54 52 ),
55 53 )
@@ -56,9 +54,9 @@
56 54 );
57 55
58 56 // Fullscreen toggle — sits next to "Switch to Classic Admin" so the
59 57 // shell can occupy the whole screen without browser chrome. Only
60 - // makes sense in desktop mode; kept out of classic where it would
58 + // makes sense in OpenStation; kept out of classic where it would
61 59 // just be a redundant browser-fullscreen shortcut.
62 60 if ( $is_active ) {
63 61 $wp_admin_bar->add_node(
64 62 array(
@@ -78,9 +76,9 @@
78 76 // Layout menu — only surfaced when the user is actually viewing
79 77 // the desktop shell (the actions don't make sense in classic
80 78 // admin, which has no windows to arrange). Parent renders as a
81 79 // dashicon with a hover-opened submenu; each child is routed to
82 - // `wp.desktop.windowManager.*` by the inline JS.
80 + // `wp.os.windowManager.*` by the inline JS.
83 81 //
84 82 // Sits next to Fullscreen so the two shell-state actions group
85 83 // visually. Ask AI, then the help/meta cluster (Keyboard shortcuts
86 84 // + Report a bug) follow, with the help/meta pair anchored to the
@@ -104,9 +102,9 @@
104 102 'id' => 'desktop-layout-cascade',
105 103 'title' => esc_html__( 'Cascade', 'desktop-mode' ),
106 104 'href' => '#',
107 105 'meta' => array(
108 - 'class' => 'desktop-mode-layout-action',
106 + 'class' => 'os-layout-action',
109 107 'title' => __( 'Lay all windows out from top-left, offset so every title bar stays visible.', 'desktop-mode' ),
110 108 ),
111 109 )
112 110 );
@@ -116,9 +114,9 @@
116 114 'id' => 'desktop-layout-overview',
117 115 'title' => esc_html__( 'Overview', 'desktop-mode' ),
118 116 'href' => '#',
119 117 'meta' => array(
120 - 'class' => 'desktop-mode-layout-action',
118 + 'class' => 'os-layout-action',
121 119 'title' => __( 'Zoom out to see every window at once. Click one to focus it.', 'desktop-mode' ),
122 120 ),
123 121 )
124 122 );
@@ -130,13 +128,13 @@
130 128 $wp_admin_bar->add_node(
131 129 array(
132 130 'parent' => 'desktop-layout-menu',
133 131 'id' => 'desktop-layout-snap',
134 - 'title' => '<span class="desktop-mode-layout-checkbox" aria-hidden="true">☐</span> '
132 + 'title' => '<span class="os-layout-checkbox" aria-hidden="true">☐</span> '
135 133 . esc_html__( 'Snap to grid', 'desktop-mode' ),
136 134 'href' => '#',
137 135 'meta' => array(
138 - 'class' => 'desktop-mode-layout-snap',
136 + 'class' => 'os-layout-snap',
139 137 'title' => __( 'Snap windows to a grid while dragging or resizing.', 'desktop-mode' ),
140 138 ),
141 139 )
142 140 );
@@ -146,9 +144,9 @@
146 144 'id' => 'desktop-layout-tile',
147 145 'title' => esc_html__( 'Tile all windows', 'desktop-mode' ),
148 146 'href' => '#',
149 147 'meta' => array(
150 - 'class' => 'desktop-mode-layout-action',
148 + 'class' => 'os-layout-action',
151 149 'title' => __( 'Pack every window into an evenly tiled grid that fills the desktop.', 'desktop-mode' ),
152 150 ),
153 151 )
154 152 );
@@ -157,9 +155,9 @@
157 155 * Filter the list of custom arrange-menu items contributed by
158 156 * plugins. Each entry becomes an additional node under the
159 157 * "Arrange" submenu, rendered with the same styling as the
160 158 * built-in Cascade / Overview / Tile items. Clicking a custom
161 - * item dispatches the JS action `desktop-mode.arrange.custom-action`
159 + * item dispatches the JS action `os.arrange.custom-action`
162 160 * with payload `{ id }` — plugins subscribe via
163 161 * `wp.hooks.addAction()` and run their own arrangement logic.
164 162 *
165 163 * Each item is an associative array:
@@ -172,13 +170,11 @@
172 170 * 10+ to append.
173 171 *
174 172 * Entries with missing/invalid `id` or `title` are dropped.
175 173 *
176 - * @since 0.6.2
177 - *
178 174 * @param array $items Existing custom items (default empty).
179 175 */
180 - $custom = apply_filters( 'desktop_mode_arrange_menu_items', array() );
176 + $custom = apply_filters( 'openstation_arrange_menu_items', array() );
181 177 if ( is_array( $custom ) ) {
182 178 // Stable sort by `position` (default 10 — after built-ins),
183 179 // preserving registration order within a tie.
184 180 $sortable = array();
@@ -222,9 +218,9 @@
222 218 'id' => 'desktop-layout-custom-' . $item['id'],
223 219 'title' => esc_html( $item['title'] ),
224 220 'href' => '#',
225 221 'meta' => array(
226 - 'class' => 'desktop-mode-layout-action desktop-mode-layout-custom',
222 + 'class' => 'os-layout-action os-layout-custom',
227 223 'title' => $item['description'],
228 224 ),
229 225 )
230 226 );
@@ -231,41 +227,19 @@
231 227 }
232 228 }
233 229 }
234 230
235 - // AI Assistant trigger — shown when desktop mode is active AND the
236 - // current user has AI features configured. Clicking (or pressing
237 - // Cmd+K anywhere) opens the spotlight-style AI overlay.
238 - if ( $is_active && function_exists( 'desktop_mode_ai_is_enabled' ) && desktop_mode_ai_is_enabled( get_current_user_id() ) ) {
239 - // Use dashicons-admin-comments (speech bubble) — same rendering
240 - // path as the toggle + arrange buttons, no SVG / HTML parsing
241 - // issues in the admin-bar context. The ⌘K badge is added via
242 - // a CSS ::after on the label so it never touches the DOM.
243 - $wp_admin_bar->add_node(
244 - array(
245 - 'parent' => 'top-secondary',
246 - 'id' => 'desktop-ai-assistant',
247 - 'title' => '<span class="ab-icon dashicons dashicons-admin-comments" aria-hidden="true"></span>'
248 - . '<span class="ab-label">' . esc_html__( 'Ask AI', 'desktop-mode' ) . '</span>',
249 - 'href' => '#',
250 - 'meta' => array(
251 - 'class' => 'desktop-ai-btn',
252 - 'title' => __( 'Open AI Assistant (Cmd+K)', 'desktop-mode' ),
253 - 'tabindex' => 0,
254 - ),
255 - )
256 - );
257 - }
258 -
259 - // "Keyboard shortcuts" trigger — shown only when desktop mode is
260 - // active. Dispatches `desktop-mode-open-help` on click; the shell
261 - // answers by opening the Keyboard Shortcuts reference window.
231 + // "Keyboard shortcuts" trigger — shown only when OpenStation is
232 + // active. Clicking toggles the keyboard-shortcuts popover wired by
233 + // assets/js/admin-bar.js (wireShortcutsPopover); the popover content
234 + // is translated server-side and shipped via the `shortcuts` key of
235 + // the openStationAdminBar config blob below.
262 236 if ( $is_active ) {
263 237 $wp_admin_bar->add_node(
264 238 array(
265 239 'parent' => 'top-secondary',
266 240 'id' => 'desktop-help',
267 - 'title' => '<span class="ab-icon desktop-mode-keyboard-icon" aria-hidden="true"></span>',
241 + 'title' => '<span class="ab-icon os-keyboard-icon" aria-hidden="true"></span>',
268 242 'href' => '#',
269 243 'meta' => array(
270 244 'class' => 'desktop-help-btn',
271 245 'title' => __( 'Keyboard shortcuts', 'desktop-mode' ),
@@ -274,10 +248,10 @@
274 248 )
275 249 );
276 250 }
277 251
278 - // "Report a bug" trigger — shown only when desktop mode is active.
279 - // Clicking dispatches a `desktop-mode-open-bug-report` document
252 + // "Report a bug" trigger — shown only when OpenStation is active.
253 + // Clicking dispatches a `os-open-bug-report` document
280 254 // CustomEvent that the shell listens for and answers by opening the
281 255 // Bug Report native window. PHP doesn't know the JS side exists; the
282 256 // event lets us add the button without coupling to any specific
283 257 // shell module. Anchored to the far right of the secondary bar so
@@ -299,37 +273,62 @@
299 273 )
300 274 );
301 275 }
302 276 }
303 -add_action( 'admin_bar_menu', 'desktop_mode_admin_bar_toggle', 190 );
277 +add_action( 'admin_bar_menu', 'openstation_admin_bar_toggle', 190 );
304 278
305 279 /**
306 - * Enqueues the inline CSS and JS for the desktop mode toggle.
280 + * Enqueues the CSS and JS for the OpenStation toggle.
307 281 *
308 - * Uses `admin-bar` as the carrier handle so the inline assets always ship
309 - * with the admin bar itself — no matter which admin screen is showing.
310 - *
311 - * @since 0.1.0
282 + * The CSS is inline, attached to the `admin-bar` style handle so it always
283 + * ships with the admin bar itself — no matter which admin screen is showing.
284 + * The JS is the external assets/js/admin-bar.js bundle, registered as
285 + * `os-admin-bar` with `admin-bar` as a dependency; its config is
286 + * emitted as an inline JSON literal `before` the script.
312 287 */
313 -function desktop_mode_enqueue_toggle_assets() {
288 +function openstation_enqueue_toggle_assets() {
314 289 if ( ! is_admin() || ! is_user_logged_in() ) {
315 290 return;
316 291 }
317 292
293 + // Inside a chromeless window the admin bar is suppressed outright
294 + // (`show_admin_bar` + the `wp_admin_bar_render` removal in
295 + // helpers.php), so `#wpadminbar` never reaches the DOM. Every byte
296 + // below — the toggle bundle, its inline config, the node styling —
297 + // would load and run against markup that does not exist. Measured
298 + // on a live install: the toggle bundle alone was 17.7 KB, the
299 + // largest single asset in the admin-bar family a window loaded for
300 + // nothing. See `includes/render/chromeless-trim.php`, which drops
301 + // the rest of that family (core's `admin-bar`, host masterbar
302 + // extras) for the same reason.
303 + if ( openstation_is_chromeless_request() ) {
304 + return;
305 + }
306 +
307 + // The items are `display: flex`, never `inline-flex`. An
308 + // inline-level box sits on a line box the <li> lays out at its
309 + // 32px line-height and aligns on the baseline, so the line grows
310 + // by the descender: the item became 37px inside a 32px bar. Under
311 + // Core's float layout that overflow was invisible. On a host that
312 + // lays the secondary group out as a flex row (WordPress.com's Debug
313 + // Bar does, to order its own item first) every sibling stretched
314 + // to the tallest one and the group's background painted 5px into
315 + // the shell, under the windows' title bars. Block-level, the item
316 + // is exactly the bar. `Tests_OpenStation_AdminBarDesktopToggle`
317 + // pins it; `desktop.css` caps the group as well, for items we do
318 + // not own.
318 319 $css = '
319 - #wpadminbar #wp-admin-bar-desktop-mode-toggle > .ab-item,
320 + #wpadminbar #wp-admin-bar-os-toggle > .ab-item,
320 321 #wpadminbar #wp-admin-bar-desktop-layout-menu > .ab-item,
321 - #wpadminbar #wp-admin-bar-desktop-ai-assistant > .ab-item,
322 322 #wpadminbar #wp-admin-bar-desktop-fullscreen > .ab-item,
323 323 #wpadminbar #wp-admin-bar-desktop-bug-report > .ab-item,
324 324 #wpadminbar #wp-admin-bar-desktop-help > .ab-item {
325 - display: inline-flex;
325 + display: flex;
326 326 align-items: center;
327 327 gap: 6px;
328 328 }
329 - #wpadminbar #wp-admin-bar-desktop-mode-toggle .ab-icon,
329 + #wpadminbar #wp-admin-bar-os-toggle .ab-icon,
330 330 #wpadminbar #wp-admin-bar-desktop-layout-menu .ab-icon,
331 - #wpadminbar #wp-admin-bar-desktop-ai-assistant .ab-icon,
332 331 #wpadminbar #wp-admin-bar-desktop-fullscreen .ab-icon,
333 332 #wpadminbar #wp-admin-bar-desktop-bug-report .ab-icon,
334 333 #wpadminbar #wp-admin-bar-desktop-help .ab-icon {
335 334 float: none;
@@ -341,15 +340,15 @@
341 340 width: 20px;
342 341 height: 20px;
343 342 }
344 343
345 - #wp-admin-bar-desktop-mode-toggle .ab-icon.dashicons,
344 + #wp-admin-bar-os-toggle .ab-icon.dashicons,
346 345 #wp-admin-bar-desktop-layout-menu .ab-icon.dashicons {
347 346 font: normal 20px/1 dashicons;
348 347 -webkit-font-smoothing: antialiased;
349 348 -moz-osx-font-smoothing: grayscale;
350 349 }
351 - #wp-admin-bar-desktop-mode-toggle .ab-icon.dashicons::before {
350 + #wp-admin-bar-os-toggle .ab-icon.dashicons::before {
352 351 content: "\f472";
353 352 top: 0;
354 353 position: static;
355 354 }
@@ -358,9 +357,9 @@
358 357 content: "\f509";
359 358 top: 0;
360 359 position: static;
361 360 }
362 - #wp-admin-bar-desktop-mode-toggle.desktop-mode-active .ab-icon.dashicons::before {
361 + #wp-admin-bar-os-toggle.os-active .ab-icon.dashicons::before {
363 362 /* Inherit the admin-bar text color so the active state
364 363 matches the +New, Home, Comments dashicons. Previously
365 364 hardcoded #72aee6, which forced blue regardless of the
366 365 profile color scheme. */
@@ -366,60 +365,13 @@
366 365 profile color scheme. */
367 366 color: inherit;
368 367 }
369 368 @media screen and (max-width: 782px) {
370 - #wp-admin-bar-desktop-mode-toggle .ab-label {
369 + #wp-admin-bar-os-toggle .ab-label {
371 370 display: none;
372 371 }
373 372 }
374 373
375 - /* AI Assistant admin-bar button — same icon/label pattern as the
376 - desktop-mode-toggle; ⌘K badge added via CSS ::after so we keep
377 - the title HTML clean and avoid admin-bar sanitisation edge-cases. */
378 - #wp-admin-bar-desktop-ai-assistant .ab-icon.dashicons,
379 - #wp-admin-bar-desktop-ai-assistant .ab-icon.dashicons {
380 - font: normal 20px/1 dashicons;
381 - -webkit-font-smoothing: antialiased;
382 - -moz-osx-font-smoothing: grayscale;
383 - }
384 - #wp-admin-bar-desktop-ai-assistant .ab-icon.dashicons::before {
385 - content: "\f101";
386 - top: 0;
387 - position: static;
388 - /* See note on desktop-mode-toggle above — inherit so the
389 - icon matches the rest of the admin-bar dashicons
390 - across all WP profile color schemes. */
391 - color: inherit;
392 - }
393 - /* ⌘K badge rendered purely in CSS to the right of the label.
394 - inline-flex + align-items:center centers the glyph inside
395 - its own padding box; a 1px upward translate compensates
396 - for the optical sag from the admin-bar label baseline. */
397 - #wpadminbar #wp-admin-bar-desktop-ai-assistant .ab-label::after {
398 - content: "\2318K";
399 - display: inline-flex;
400 - align-items: center;
401 - justify-content: center;
402 - margin-inline-start: 5px;
403 - font-size: 10px;
404 - line-height: 1;
405 - padding: 2px 5px;
406 - background: rgba( 255, 255, 255, 0.1 );
407 - border: 1px solid rgba( 255, 255, 255, 0.18 );
408 - border-radius: 3px;
409 - color: rgba( 255, 255, 255, 0.55 );
410 - vertical-align: middle;
411 - font-weight: 400;
412 - letter-spacing: 0;
413 - position: relative;
414 - top: -1px;
415 - }
416 - @media screen and (max-width: 782px) {
417 - #wp-admin-bar-desktop-ai-assistant .ab-label {
418 - display: none;
419 - }
420 - }
421 -
422 374 /* Fullscreen admin-bar button — same dashicons rendering pattern
423 375 as the toggle. Icon swaps between fullscreen-alt (enter) and
424 376 fullscreen-exit-alt (exit) via the .is-fullscreen class set by
425 377 admin-bar.js on `fullscreenchange`. */
@@ -459,10 +411,10 @@
459 411 where pointer events get intercepted before reaching the
460 412 page. Hiding these two shifts the Fullscreen toggle further
461 413 from the corner so its own click lands. Toggled by a body
462 414 class admin-bar.js sets on `fullscreenchange`. */
463 - body.desktop-mode-browser-fs #wp-admin-bar-desktop-mode-toggle,
464 - body.desktop-mode-browser-fs #wp-admin-bar-desktop-bug-report {
415 + body.os-browser-fs #wp-admin-bar-os-toggle,
416 + body.os-browser-fs #wp-admin-bar-desktop-bug-report {
465 417 display: none;
466 418 }
467 419
468 420 /* Bug Report admin-bar button — same dashicons rendering pattern
@@ -486,9 +438,9 @@
486 438 glyph, so we paint a small inline SVG via CSS `mask` with
487 439 `background-color: currentColor` — that way the icon inherits
488 440 the admin-bar text color across every WP profile scheme
489 441 without us hardcoding a fill. */
490 - #wp-admin-bar-desktop-help .ab-icon.desktop-mode-keyboard-icon {
442 + #wp-admin-bar-desktop-help .ab-icon.os-keyboard-icon {
491 443 background-color: currentColor;
492 444 -webkit-mask: url( "data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'black\' stroke-width=\'1.6\' stroke-linecap=\'round\' stroke-linejoin=\'round\'><rect x=\'2.5\' y=\'6\' width=\'19\' height=\'12\' rx=\'2.2\'/><path d=\'M6 10h0M10 10h0M14 10h0M18 10h0M6 14h0M10 14h4M18 14h0\'/></svg>" ) no-repeat center / 20px 20px;
493 445 mask: url( "data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'black\' stroke-width=\'1.6\' stroke-linecap=\'round\' stroke-linejoin=\'round\'><rect x=\'2.5\' y=\'6\' width=\'19\' height=\'12\' rx=\'2.2\'/><path d=\'M6 10h0M10 10h0M14 10h0M18 10h0M6 14h0M10 14h4M18 14h0\'/></svg>" ) no-repeat center / 20px 20px;
494 446 }
@@ -496,13 +448,13 @@
496 448 /* Keyboard-shortcuts floating popover — anchored under the
497 449 keyboard button. Styled to match the Arrange submenu (light
498 450 bg on the otherwise-dark admin bar, soft shadow, rounded
499 451 corners). Built dynamically in admin-bar.js from translated
500 - content shipped via `desktopModeAdminBar.shortcuts`. */
452 + content shipped via `openStationAdminBar.shortcuts`. */
501 453 #wpadminbar #wp-admin-bar-desktop-help {
502 454 position: relative;
503 455 }
504 - #wpadminbar .desktop-mode-shortcuts-popover {
456 + #wpadminbar .os-shortcuts-popover {
505 457 display: none;
506 458 position: absolute;
507 459 top: 100%;
508 460 right: 0;
@@ -509,11 +461,11 @@
509 461 margin-top: 0;
510 462 padding: 12px 14px;
511 463 min-width: 460px;
512 464 max-width: min( 90vw, 720px );
513 - background: var( --desktop-mode-window-bg, #fff );
514 - color: var( --desktop-mode-text, #1d2327 );
515 - border: 1px solid var( --desktop-mode-window-border, #c3c4c7 );
465 + background: var( --os-ui-surface, var( --os-window-bg, #fff ) );
466 + color: var( --os-ui-fg, #1d2327 );
467 + border: 1px solid var( --os-ui-border, var( --os-window-border, #c3c4c7 ) );
516 468 border-radius: 8px;
517 469 box-shadow: 0 8px 24px rgba( 0, 0, 0, 0.18 ),
518 470 0 2px 6px rgba( 0, 0, 0, 0.08 );
519 471 z-index: 99999;
@@ -520,15 +472,15 @@
520 472 font-size: 12px;
521 473 line-height: 1.4;
522 474 text-align: left;
523 475 }
524 - #wpadminbar .desktop-mode-shortcuts-popover.is-open {
476 + #wpadminbar .os-shortcuts-popover.is-open {
525 477 display: block;
526 478 }
527 - #wpadminbar .desktop-mode-shortcuts-popover__section + .desktop-mode-shortcuts-popover__section {
479 + #wpadminbar .os-shortcuts-popover__section + .os-shortcuts-popover__section {
528 480 margin-top: 12px;
529 481 }
530 - #wpadminbar .desktop-mode-shortcuts-popover__heading {
482 + #wpadminbar .os-shortcuts-popover__heading {
531 483 margin: 0 0 6px;
532 484 padding: 0;
533 485 font-size: 11px;
534 486 font-weight: 600;
@@ -533,44 +485,44 @@
533 485 font-size: 11px;
534 486 font-weight: 600;
535 487 letter-spacing: 0.04em;
536 488 text-transform: uppercase;
537 - color: var( --desktop-mode-muted-fg, #50575e );
489 + color: var( --os-ui-fg-muted, #50575e );
538 490 line-height: 1.2;
539 491 }
540 - #wpadminbar .desktop-mode-shortcuts-popover__table {
492 + #wpadminbar .os-shortcuts-popover__table {
541 493 width: 100%;
542 494 border-collapse: collapse;
543 495 color: inherit;
544 496 }
545 - #wpadminbar .desktop-mode-shortcuts-popover__table th,
546 - #wpadminbar .desktop-mode-shortcuts-popover__table td {
497 + #wpadminbar .os-shortcuts-popover__table th,
498 + #wpadminbar .os-shortcuts-popover__table td {
547 499 padding: 6px 8px;
548 500 vertical-align: middle;
549 501 text-align: left;
550 - border-bottom: 1px solid rgba( 0, 0, 0, 0.06 );
502 + border-bottom: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.06 ) );
551 503 color: inherit;
552 504 font-weight: 400;
553 505 font-size: 12px;
554 506 line-height: 1.4;
555 507 }
556 - #wpadminbar .desktop-mode-shortcuts-popover__table th {
508 + #wpadminbar .os-shortcuts-popover__table th {
557 509 font-weight: 600;
558 510 font-size: 11px;
559 - color: var( --desktop-mode-muted-fg, #50575e );
511 + color: var( --os-ui-fg-muted, #50575e );
560 512 letter-spacing: 0.02em;
561 513 }
562 - #wpadminbar .desktop-mode-shortcuts-popover__table tbody tr:last-child td {
514 + #wpadminbar .os-shortcuts-popover__table tbody tr:last-child td {
563 515 border-bottom: none;
564 516 }
565 - #wpadminbar .desktop-mode-shortcuts-popover__key-cell {
517 + #wpadminbar .os-shortcuts-popover__key-cell {
566 518 white-space: nowrap;
567 519 }
568 - #wpadminbar .desktop-mode-shortcuts-popover__note {
569 - color: var( --desktop-mode-muted-fg, #50575e );
520 + #wpadminbar .os-shortcuts-popover__note {
521 + color: var( --os-ui-fg-muted, #50575e );
570 522 font-size: 11px;
571 523 }
572 - #wpadminbar .desktop-mode-shortcuts-popover__list {
524 + #wpadminbar .os-shortcuts-popover__list {
573 525 margin: 0;
574 526 padding: 0;
575 527 list-style: none;
576 528 display: flex;
@@ -576,9 +528,9 @@
576 528 display: flex;
577 529 flex-direction: column;
578 530 gap: 4px;
579 531 }
580 - #wpadminbar .desktop-mode-shortcuts-popover__item {
532 + #wpadminbar .os-shortcuts-popover__item {
581 533 display: grid;
582 534 grid-template-columns: 120px 1fr;
583 535 align-items: center;
584 536 gap: 12px;
@@ -583,17 +535,17 @@
583 535 align-items: center;
584 536 gap: 12px;
585 537 padding: 4px 8px;
586 538 border-radius: 4px;
587 - background: rgba( 0, 0, 0, 0.03 );
539 + background: var( --os-ui-surface-sunken, rgba( 0, 0, 0, 0.03 ) );
588 540 }
589 - #wpadminbar .desktop-mode-shortcuts-popover__keys {
541 + #wpadminbar .os-shortcuts-popover__keys {
590 542 display: inline-flex;
591 543 align-items: center;
592 544 gap: 4px;
593 545 flex-wrap: wrap;
594 546 }
595 - #wpadminbar .desktop-mode-shortcuts-popover__kbd {
547 + #wpadminbar .os-shortcuts-popover__kbd {
596 548 display: inline-flex;
597 549 align-items: center;
598 550 justify-content: center;
599 551 min-width: 22px;
@@ -598,13 +550,13 @@
598 550 justify-content: center;
599 551 min-width: 22px;
600 552 height: 20px;
601 553 padding: 0 5px;
602 - border: 1px solid rgba( 0, 0, 0, 0.18 );
554 + border: 1px solid var( --os-ui-border-strong, rgba( 0, 0, 0, 0.18 ) );
603 555 border-bottom-width: 2px;
604 556 border-radius: 4px;
605 - background: #fff;
606 - color: var( --desktop-mode-text, #1d2327 );
557 + background: var( --os-ui-surface-elevated, #fff );
558 + color: var( --os-ui-fg, #1d2327 );
607 559 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
608 560 font-size: 11px;
609 561 font-weight: 600;
610 562 line-height: 1;
@@ -609,13 +561,13 @@
609 561 font-weight: 600;
610 562 line-height: 1;
611 563 white-space: nowrap;
612 564 }
613 - #wpadminbar .desktop-mode-shortcuts-popover__plus {
565 + #wpadminbar .os-shortcuts-popover__plus {
614 566 font-size: 10px;
615 - color: var( --desktop-mode-muted-fg, #50575e );
567 + color: var( --os-ui-fg-muted, #50575e );
616 568 }
617 - #wpadminbar .desktop-mode-shortcuts-popover__description {
569 + #wpadminbar .os-shortcuts-popover__description {
618 570 color: inherit;
619 571 }
620 572
621 573 /* Dock-style custom tooltip for icon-only admin-bar buttons.
@@ -657,21 +609,29 @@
657 609 #wpadminbar #wp-admin-bar-desktop-help.is-open .ab-item[ data-desktop-tooltip ]::after {
658 610 opacity: 0;
659 611 }
660 612
661 - /* Arrange submenu — aligned visually with the <wpd-menu> component
662 - (src/ui/components/wpd-menu/wpd-menu.styles.ts). The submenu
663 - flips from the native dark-on-dark admin bar to a light theme
664 - (white bg, dark text) so it matches the rest of our UI AND so
665 - the hover state stays legible (a light tint on a dark bg
666 - would render as invisible overlap with native admin-bar hover
667 - colors). Selectors prefixed with #wpadminbar to win the
668 - admin-bar specificity without !important. */
613 + /* Arrange submenu — aligned visually with the <os-menu> component
614 + (src/ui/components/os-menu/os-menu.styles.ts). The submenu
615 + breaks out of the native dark-on-dark admin bar and paints
616 + itself from the `--os-ui-*` panel palette instead, so it matches
617 + the rest of our UI and stays legible under any desktop theme.
618 +
619 + Surface and text MUST come from the same palette. They used to
620 + not: the background read `--os-window-bg` (which a
621 + theme sets) while the text read `--os-text` (which
622 + nothing has ever defined, so it always fell back to near-black).
623 + Any dark theme therefore rendered near-black text on its own
624 + near-black panel. Keep both sides on `--os-ui-surface` /
625 + `--os-ui-fg` and that class of bug cannot come back.
626 +
627 + Selectors prefixed with #wpadminbar to win the admin-bar
628 + specificity without !important. */
669 629 #wpadminbar #wp-admin-bar-desktop-layout-menu .ab-sub-wrapper {
670 - background: var( --desktop-mode-window-bg, #fff );
630 + background: var( --os-ui-surface, var( --os-window-bg, #fff ) );
671 631 padding: 4px;
672 632 min-width: 220px;
673 - border: 1px solid var( --desktop-mode-window-border, #c3c4c7 );
633 + border: 1px solid var( --os-ui-border, var( --os-window-border, #c3c4c7 ) );
674 634 border-radius: 8px;
675 635 box-shadow: 0 8px 24px rgba( 0, 0, 0, 0.18 ),
676 636 0 2px 6px rgba( 0, 0, 0, 0.08 );
677 637 }
@@ -690,9 +650,9 @@
690 650 min-height: 32px;
691 651 padding: 6px 10px;
692 652 font-size: 13px;
693 653 line-height: 1.3;
694 - color: var( --desktop-mode-text, #1d2327 );
654 + color: var( --os-ui-fg, #1d2327 );
695 655 background: transparent;
696 656 border-radius: 6px;
697 657 transition: background-color 0.12s ease, color 0.12s ease;
698 658 }
@@ -702,12 +662,12 @@
702 662 thanks to the extra id in our selector chain. */
703 663 #wpadminbar #wp-admin-bar-desktop-layout-menu .ab-sub-wrapper .ab-submenu > li > .ab-item:hover,
704 664 #wpadminbar #wp-admin-bar-desktop-layout-menu .ab-sub-wrapper .ab-submenu > li > .ab-item:focus,
705 665 #wpadminbar.nojq #wp-admin-bar-desktop-layout-menu .ab-sub-wrapper .ab-submenu > li:hover > .ab-item {
706 - background: rgba( 0, 0, 0, 0.06 );
707 - color: #000;
666 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) );
667 + color: var( --os-ui-fg, #000 );
708 668 }
709 - #wp-admin-bar-desktop-layout-snap .desktop-mode-layout-checkbox {
669 + #wp-admin-bar-desktop-layout-snap .os-layout-checkbox {
710 670 flex-shrink: 0;
711 671 display: inline-flex;
712 672 align-items: center;
713 673 justify-content: center;
@@ -715,9 +675,9 @@
715 675 height: 16px;
716 676 font-size: 14px;
717 677 line-height: 1;
718 678 }
719 - #wp-admin-bar-desktop-layout-snap[aria-checked="true"] .desktop-mode-layout-checkbox {
679 + #wp-admin-bar-desktop-layout-snap[aria-checked="true"] .os-layout-checkbox {
720 680 color: var( --wp-admin-theme-color, #2271b1 );
721 681 }
722 682 ';
723 683 wp_add_inline_style( 'admin-bar', $css );
@@ -725,18 +685,18 @@
725 685 // All PHP→JS values are emitted as JSON literals (never interpolated
726 686 // raw into the script body) so special characters, quotes, and
727 687 // unexpected shapes can't break the parser or be exploited.
728 688 // `active` must match the visual state shown on the toggle above —
729 - // i.e. "currently viewing desktop mode." Using `desktop_mode_is_enabled()`
689 + // i.e. "currently viewing OpenStation." Using `openstation_is_enabled()`
730 690 // alone would misclassify a classic-override request (meta = '1',
731 691 // URL carrying `desktop_mode_classic=1`) as active, causing the
732 692 // click handler to send `enabled=0` when the user actually wants
733 693 // to return to the shell.
734 694 wp_register_script(
735 - 'desktop-mode-admin-bar',
736 - DESKTOP_MODE_URL . 'assets/js/admin-bar.js',
695 + 'os-admin-bar',
696 + OPENSTATION_URL . 'assets/js/admin-bar.js',
737 697 array( 'admin-bar' ),
738 - DESKTOP_MODE_VERSION,
698 + OPENSTATION_VERSION,
739 699 true
740 700 );
741 701 // Emit the config as a JSON literal via wp_add_inline_script (not
742 702 // wp_localize_script — the latter casts booleans to '' / '1', which
@@ -742,15 +702,21 @@
742 702 // wp_localize_script — the latter casts booleans to '' / '1', which
743 703 // breaks the click handler's `!! cfg.active` check). 'before' runs
744 704 // before admin-bar.js so the global is ready when the IIFE fires.
745 705 wp_add_inline_script(
746 - 'desktop-mode-admin-bar',
747 - 'var desktopModeAdminBar = ' . wp_json_encode(
706 + 'os-admin-bar',
707 + 'var openStationAdminBar = ' . wp_json_encode(
748 708 array(
749 - 'nonce' => wp_create_nonce( 'save-desktop-mode' ),
750 - 'active' => desktop_mode_is_enabled() && ! desktop_mode_is_classic_request(),
751 - 'classicUrl' => esc_url_raw( admin_url() ),
752 - 'portalUrl' => esc_url_raw( desktop_mode_portal_url() ),
709 + 'nonce' => wp_create_nonce( 'save-openstation' ),
710 + 'active' => openstation_is_enabled() && ! openstation_is_classic_request(),
711 + // `self_admin_url()`: switching off from the network
712 + // admin returns there, not to the main site.
713 + 'classicUrl' => esc_url_raw( self_admin_url() ),
714 + 'portalUrl' => esc_url_raw( openstation_portal_url() ),
715 + // Passed back on the toggle's AJAX call: the handler
716 + // runs on `admin-ajax.php`, where `is_network_admin()`
717 + // is always false.
718 + 'network' => is_network_admin(),
753 719 'ajaxUrl' => esc_url_raw( admin_url( 'admin-ajax.php' ) ),
754 720 'i18n' => array(
755 721 'enterFullscreen' => __( 'Fullscreen', 'desktop-mode' ),
756 722 'exitFullscreen' => __( 'Exit fullscreen', 'desktop-mode' ),
@@ -756,8 +722,9 @@
756 722 'exitFullscreen' => __( 'Exit fullscreen', 'desktop-mode' ),
757 723 'enterTitle' => __( 'Enter fullscreen', 'desktop-mode' ),
758 724 'exitTitle' => __( 'Exit fullscreen', 'desktop-mode' ),
759 725 ),
726 +
760 727 /*
761 728 * Keyboard-shortcuts popover content. Translated once on
762 729 * the server and shipped to admin-bar.js, which renders
763 730 * the popover anchored under the keyboard button.
@@ -827,8 +794,12 @@
827 794 'keys' => array( '⌘/Ctrl', 'K' ),
828 795 'description' => __( 'Open the command palette / Ask AI overlay.', 'desktop-mode' ),
829 796 ),
830 797 array(
798 + 'keys' => array( '⌥/Alt', '⌘/Ctrl', 'W' ),
799 + 'description' => __( 'Close every open window on the current desktop (asks first).', 'desktop-mode' ),
800 + ),
801 + array(
831 802 'keys' => array( 'Esc' ),
832 803 'description' => __( 'Exit Overview (or Snap Overview) without changing window state.', 'desktop-mode' ),
833 804 ),
834 805 ),
@@ -837,8 +808,7 @@
837 808 )
838 809 ) . ';',
839 810 'before'
840 811 );
841 - wp_enqueue_script( 'desktop-mode-admin-bar' );
812 + wp_enqueue_script( 'os-admin-bar' );
842 813 }
843 -add_action( 'admin_enqueue_scripts', 'desktop_mode_enqueue_toggle_assets' );
844 -
814 +add_action( 'admin_enqueue_scripts', 'openstation_enqueue_toggle_assets' );