PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.8.7
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.8.7
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
desktop-mode / assets / css / chromeless.css

chromeless.css in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.8.7, at assets/css/chromeless.css

373 lines 15.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Desktop Mode — Chromeless Overrides.
3 *
4 * CSS adjustments for legacy admin pages rendered inside desktop mode
5 * iframes (chromeless mode). All rules are scoped to .desktop-mode-chromeless
6 * so they never affect the classic admin or the desktop shell.
7 *
8 * Plugin and theme developers: to add your own chromeless overrides,
9 * enqueue a stylesheet on the 'desktop_mode_chromeless_styles' action.
10 * Your CSS just needs to target .desktop-mode-chromeless as the body class.
11 *
12 * Example:
13 * add_action( 'desktop_mode_chromeless_styles', function() {
14 * wp_enqueue_style( 'my-plugin-chromeless', plugin_dir_url( __FILE__ ) . 'chromeless.css' );
15 * } );
16 *
17 * @since 0.1.0
18 */
19
20 /* ---------------------------------------------------------------
21 * Hide the classic admin chrome elements. These would otherwise
22 * reserve space (sidebar gutter, footer, admin bar) around the
23 * chromeless page content.
24 * --------------------------------------------------------------- */
25 .desktop-mode-chromeless #adminmenuwrap,
26 .desktop-mode-chromeless #adminmenuback,
27 .desktop-mode-chromeless #wpfooter,
28 .desktop-mode-chromeless #wpadminbar,
29 .desktop-mode-chromeless .wp-responsive-toggle,
30 .desktop-mode-chromeless #collapse-menu {
31 display: none !important;
32 }
33
34 /*
35 * _wp_admin_html_begin() adds the `wp-toolbar` class to <html> whenever
36 * is_admin_bar_showing() is true — which, in admin, is unconditional.
37 * The class carries a `padding-top: var(--wp-admin--admin-bar--height)`
38 * that would leave a 32px (or 46px) dead gap at the top of the iframe.
39 * Zero it out inside chromeless iframes.
40 *
41 * We also rebind `--wp-admin--admin-bar--height` (and the derived
42 * `--wp-admin--admin-bar--position-offset` from block-library) to 0px
43 * inside chromeless so plugins that position UI relative to the admin
44 * bar resolve their math against the iframe's actual chrome state.
45 *
46 * WooCommerce's activity-panel wrapper, the block editor's sticky
47 * header, and several others use `top: var(--wp-admin--admin-bar--height)`
48 * to clear the bar. Without this override they reserve a 32px (or 46px
49 * on small screens) gap that no longer exists, producing visible jumps
50 * on first paint and dead space at the top of the content area.
51 */
52 html.wp-toolbar:has( body.desktop-mode-chromeless ) {
53 padding-top: 0 !important;
54 --wp-admin--admin-bar--height: 0px;
55 --wp-admin--admin-bar--position-offset: 0px;
56 }
57
58 /* Remove the sidebar gutter on #wpcontent and let the body fill the frame. */
59 .desktop-mode-chromeless #wpcontent {
60 margin-inline-start: 0 !important;
61 padding-inline-start: 0 !important;
62 }
63
64 /*
65 * WooCommerce sidebar-reservation override.
66 *
67 * `.woocommerce-layout__header` is a `position: fixed` bar WC
68 * mounts on every wc-admin and wc-embedded page. Its width is
69 * compiled from the SCSS source (header/style.scss) as a literal:
70 *
71 * position: fixed;
72 * top: 32px; // $adminbar-height
73 * width: calc(100% - 160px); // reserves classic sidebar
74 * z-index: 1001;
75 *
76 * The 160px subtraction is the classic admin menu width — WC bakes
77 * it in at build time so the header doesn't overlap the sidebar
78 * in standard admin. Inside chromeless we hide the sidebar, but
79 * the header keeps the reservation — so the header ends 160px
80 * short of the iframe right edge, and `.woocommerce-layout__activity-panel-wrapper`
81 * (`position: absolute; right: 0; top: 100%; transform: translateX(100%)`,
82 * containing block = the fixed header) translates past the
83 * header's right edge, NOT past the iframe's right edge. The
84 * resulting visible strip is exactly 160px wide — the size of the
85 * sidebar gap WC reserved for nothing.
86 *
87 * Reclaim the reservation: pin the header to full iframe width
88 * inside chromeless. The activity panel then translates past the
89 * iframe edge as WC's design intended, the gray strip disappears,
90 * and the header's content uses the full window width. No
91 * transform / overflow / visibility tricks needed.
92 */
93 .desktop-mode-chromeless .woocommerce-layout__header {
94 width: 100% !important;
95 }
96
97 /* ---------------------------------------------------------------
98 * Screen Meta (Screen Options / Help panels)
99 * The toggle buttons (#screen-meta-links) are hidden because
100 * the parent desktop shell adds its own buttons to the window
101 * title bar. The panels themselves stay visible and functional —
102 * they're toggled via postMessage from the parent.
103 *
104 * Collapse all margins on the hidden links and the panel container
105 * so they don't leave a gap at the top of the iframe content.
106 * --------------------------------------------------------------- */
107 .desktop-mode-chromeless #screen-meta-links {
108 display: none;
109 margin: 0;
110 }
111
112 .desktop-mode-chromeless #screen-meta {
113 margin: 0;
114 border: none;
115 }
116
117 /* ---------------------------------------------------------------
118 * Wrap container
119 * Remove the default left margin that accounts for the sidebar
120 * which doesn't exist in chromeless mode.
121 * --------------------------------------------------------------- */
122 .desktop-mode-chromeless .wrap {
123 margin: 0;
124 }
125
126 /* ---------------------------------------------------------------
127 * Page title & header
128 * The window title bar already shows the page title, and the
129 * submenu tab strip below it already exposes actions like
130 * "Add New". Hide the in-page <h1>, the adjacent action button
131 * (.page-title-action), and the header separator (.wp-header-end)
132 * so the window content starts flush without a redundant header.
133 *
134 * Plugins that need their action button to remain visible can
135 * override these rules by enqueueing CSS on the
136 * 'desktop_mode_chromeless_styles' action.
137 * --------------------------------------------------------------- */
138 .desktop-mode-chromeless .wrap > h1,
139 .desktop-mode-chromeless .wrap > h1.wp-heading-inline,
140 .desktop-mode-chromeless #wpbody-content > .wrap > h1,
141 .desktop-mode-chromeless .wrap > .page-title-action,
142 .desktop-mode-chromeless .wrap > .wp-header-end {
143 display: none;
144 }
145
146 /*
147 * Exceptions: keep .page-title-action visible where it's the only
148 * entry point to a sub-flow:
149 * - plugin-install.php → "Upload Plugin"
150 * - theme-install.php → "Upload Theme"
151 *
152 * themes.php's native "Add Theme" page-title-action used to live
153 * here, but the iframe scrolled past it on load (the focus-target
154 * heuristic on the visible theme grid stole the scroll position),
155 * which made the only entry point to theme-install.php disappear.
156 * The Appearance window now ships an "Add Theme" tab in the
157 * submenu strip (see desktop_mode_inject_appearance_tabs in
158 * includes/themes-tabs.php), so the in-page button is redundant
159 * and stays hidden.
160 *
161 * The theme-install.php "Upload Theme" exception is necessary
162 * because the upload form is its own sub-flow with no equivalent
163 * affordance elsewhere in the chromeless shell — without this
164 * rule, users who want to install a .zip theme have no entry
165 * point.
166 *
167 * See issue #38.
168 */
169 .desktop-mode-chromeless.plugin-install-php .wrap > .page-title-action,
170 .desktop-mode-chromeless.theme-install-php .wrap > .page-title-action {
171 display: inline-block;
172 margin-top: 12px;
173 }
174
175 /* ---------------------------------------------------------------
176 * Dashboard welcome panel
177 * The default 16px top margin pushes the panel down and creates a
178 * visible gap at the top of the iframe. Collapse it in chromeless
179 * mode so the panel sits flush with the top of the window body.
180 * --------------------------------------------------------------- */
181 .desktop-mode-chromeless #welcome-panel,
182 .desktop-mode-chromeless .welcome-panel {
183 margin-top: 0.5em;
184 }
185
186 /* ---------------------------------------------------------------
187 * Footer
188 * The classic footer is not rendered in chromeless mode,
189 * but some pages have bottom padding assuming it exists.
190 * --------------------------------------------------------------- */
191 .desktop-mode-chromeless #wpbody-content {
192 margin: 0;
193 padding: 0 8px 8px;
194 float: none;
195 width: auto;
196 }
197
198 /* ---------------------------------------------------------------
199 * Block Editor — hide Gutenberg chrome that would break the window.
200 *
201 * The fullscreen-mode close button (the "W" logo top-left of the editor)
202 * is an <a href="/wp-admin/edit.php"> that navigates the iframe to a
203 * non-chromeless URL — which re-renders the entire classic admin
204 * inside our desktop window. The link interceptor in the chromeless
205 * bridge catches it too, but hiding the button removes the visual
206 * affordance so users never try to click "back to dashboard" inside
207 * what looks like a self-contained window.
208 *
209 * The site editor's equivalent navigation affordances (site hub toggle,
210 * "back to dashboard" link) get the same treatment.
211 *
212 * The welcome guide is intentionally NOT hidden anymore. Earlier
213 * iterations both CSS-hid the dialog AND flipped `core/edit-post:
214 * welcomeGuide` to `false` at the data layer on every chromeless
215 * mount — but Gutenberg already persists the user's "Get started"
216 * dismissal to user meta the moment they close it, so the override
217 * was permanently stealing the one-time orientation tour from every
218 * user who never got to see it. Modal's focus trap is Tab-only and
219 * doesn't fight the shell. Let it run. (See git history for the
220 * removed `desktop_mode_chromeless_editor_preferences` override.)
221 * --------------------------------------------------------------- */
222 .desktop-mode-chromeless .edit-post-fullscreen-mode-close,
223 .desktop-mode-chromeless .edit-post-fullscreen-mode-close__view-mode-toggle,
224 .desktop-mode-chromeless .edit-site-navigation-link,
225 .desktop-mode-chromeless .edit-site-site-hub,
226 .desktop-mode-chromeless .edit-site-site-hub__toggle {
227 display: none !important;
228 }
229
230 /* ---------------------------------------------------------------
231 * Block Editor & Site Editor — full-bleed layouts.
232 * Gutenberg owns its entire viewport (its own header bar, side
233 * panels, etc.). Any padding around #wpbody-content crops the
234 * editor and breaks its layout, so reset to zero on those pages
235 * and let the editor render edge-to-edge.
236 * --------------------------------------------------------------- */
237 .desktop-mode-chromeless.block-editor-page #wpbody-content,
238 .desktop-mode-chromeless.site-editor-php #wpbody-content,
239 .desktop-mode-chromeless.is-fullscreen-mode #wpbody-content {
240 padding: 0;
241 }
242
243 /* ---------------------------------------------------------------
244 * "Boot" SPA pages (Font Library, Options → Connectors).
245 *
246 * These screens mount a React app into `.boot-layout-container` and
247 * paint `#wpwrap` a dark `#1e1e1e` via inline <style>. Our 8px
248 * right/bottom padding on `#wpbody-content` lets that dark color
249 * bleed through as two black gaps on the right and bottom edges of
250 * the window. Zero the padding for any page hosting a boot layout
251 * — detection is purely structural (`:has()`), so a plugin that
252 * adopts the same container class inherits the fix automatically.
253 * --------------------------------------------------------------- */
254 .desktop-mode-chromeless #wpbody-content:has( .boot-layout-container ) {
255 padding: 0;
256 }
257
258 .desktop-mode-chromeless:has( .boot-layout-container ) #wpwrap {
259 /* Neutralize the inline dark background so any stray overflow
260 * matches the window body instead of flashing black. */
261 background: transparent;
262 }
263
264 /*
265 * `boot-layout__surfaces` is the white card the React app draws its
266 * content onto. In classic admin it sits on the dark #wpwrap with
267 * rounded corners and a margin that makes it read as a "card." Inside
268 * a desktop window the surface IS the content — rounded corners and
269 * side margins leave ugly bleed at the edges. Collapse it to a plain
270 * edge-to-edge surface.
271 */
272 .desktop-mode-chromeless .boot-layout__surfaces,
273 .desktop-mode-chromeless .boot-layout__stage,
274 .desktop-mode-chromeless .boot-layout__canvas {
275 border-radius: 0 !important;
276 margin: 0 !important;
277 }
278
279 /*
280 * The boot screens render their own H1 (`.boot-navigation-screen__title`,
281 * e.g., "Fonts") at the top of the surface. The desktop window already
282 * shows the page title in its title bar, so the in-page title is
283 * redundant. Visually hide it but keep it in the DOM for screen readers
284 * and for the boot app's own focus management.
285 */
286 .desktop-mode-chromeless .boot-navigation-screen__title,
287 .desktop-mode-chromeless .boot-navigation-screen__title-icon {
288 position: absolute;
289 width: 1px;
290 height: 1px;
291 padding: 0;
292 margin: -1px;
293 overflow: hidden;
294 clip: rect( 0, 0, 0, 0 );
295 white-space: nowrap;
296 border: 0;
297 }
298
299 /* ---------------------------------------------------------------
300 * Snackbars
301 *
302 * `components-snackbar-list` (Gutenberg `@wordpress/components`) and
303 * `boot-notices__snackbar` (Font Library / Connectors) position
304 * themselves `fixed` at the viewport bottom. Because a chromeless
305 * iframe IS its own viewport, those anchors already land inside the
306 * window — but our 8px bottom padding on `#wpbody-content` (applied
307 * to non-boot pages) plus some plugin-level `bottom: 40px` offsets
308 * meant for the classic admin footer can push them out of sight.
309 *
310 * Pin them flush to the bottom of the iframe and make sure nothing
311 * in the window chrome can occlude them.
312 *
313 * Triggering a snackbar to verify (desktop mode enabled):
314 * - Open Posts → Add New, save/publish → "Post published" toast.
315 * - Open Media, upload a file → "Uploaded" toast.
316 * - Open Appearance → Fonts, install a Google Font → toast.
317 * --------------------------------------------------------------- */
318 .desktop-mode-chromeless .components-snackbar-list,
319 .desktop-mode-chromeless .boot-notices__snackbar {
320 bottom: 16px !important;
321 z-index: 100000;
322 }
323
324 /*
325 * Force the Gutenberg interface skeleton to fill the iframe regardless
326 * of fullscreen state. When fullscreenMode is off, Gutenberg hardcodes
327 * `top: 32px` (admin bar reservation) and `left: 160px` (sidebar
328 * reservation) on `.interface-interface-skeleton` — both chromes we've
329 * already hidden, so those offsets become dead gaps at the top and
330 * left of the window. Zero them out unconditionally.
331 *
332 * The default is fullscreen (inset: 0), but users who turned fullscreen
333 * off in classic admin carry that preference into chromeless via the
334 * shared persistence layer. This rule keeps chromeless rendering
335 * edge-to-edge either way.
336 */
337 .desktop-mode-chromeless .interface-interface-skeleton {
338 top: 0 !important;
339 left: 0 !important;
340 right: 0 !important;
341 bottom: 0 !important;
342 }
343
344 /* ---------------------------------------------------------------
345 * Notices
346 * Give notices a bit of top margin since there's no admin bar above.
347 * --------------------------------------------------------------- */
348 .desktop-mode-chromeless .notice:first-child {
349 margin-top: 4px;
350 }
351
352 /* ---------------------------------------------------------------
353 * Update nag
354 * Red top border signals a pending WordPress update; keep it so
355 * the nag reads as urgent even without the surrounding admin chrome.
356 * --------------------------------------------------------------- */
357 .desktop-mode-chromeless .update-nag {
358 border-top: 1px solid #d63638;
359 }
360
361 /* ---------------------------------------------------------------
362 * Suppress WordPress's native command palette inside chromeless
363 * iframes. The chromeless bridge intercepts Cmd+K and forwards to
364 * the desktop shell, but if an in-page component triggers the
365 * palette via another path (programmatic dispatch, a menu item)
366 * the dialog would still render. Hide it so the shell's palette
367 * stays the only surface users ever see.
368 * --------------------------------------------------------------- */
369 .desktop-mode-chromeless .commands-command-menu__container,
370 .desktop-mode-chromeless .commands-command-menu {
371 display: none !important;
372 }
373