PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.2
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.2
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 / window-overview.css

window-overview.css in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.2, at assets/css/window-overview.css

525 lines 15.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * OpenStation — Overview.
3 *
4 * Zoom-out grid view: windows transform into thumbnails, floating
5 * labels sit above them, and a top bar lists every virtual desktop
6 * with one tile per space plus a "+" to add a new one. The dock
7 * collapses in parallel with the enter transition.
8 *
9 * Windows keep their `left/top/width/height` intact; only `transform`
10 * animates (translate + scale) so the layout change is a GPU
11 * composite, not a reflow. `transform-origin: top left` makes
12 * translate + scale compose cleanly — a target coordinate maps to
13 * the window's top-left corner pre-scale. Iframes go
14 * `pointer-events: none` inside overview so clicks hit the window
15 * wrapper (and bubble to the desktop-area click handler) instead of
16 * the iframe content, which would otherwise eat the click.
17 *
18 * Base chrome lives in window-chrome.css; non-overview state classes
19 * live in window-states.css.
20 *
21 * @since 6.9.0
22 */
23 .os-area--overview {
24 /* Darken the backdrop and tint it so windows feel like they're
25 * floating over a neutral canvas, not the wallpaper. */
26 background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) );
27 transition: background-color 0.28s ease;
28 }
29
30 .os-window--overview {
31 transform-origin: top left;
32 transition:
33 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
34 box-shadow 0.2s ease,
35 opacity 0.2s ease;
36 cursor: pointer;
37 /* Hover effects apply a thick outline rather than another
38 * transform (which would fight the layout's own transform).
39 * Box-shadow is composite-only, so it's cheap. */
40 box-shadow: 0 10px 30px rgba( 0, 0, 0, 0.35 );
41 /* Overview thumbnails are click targets, not reading surfaces —
42 * suppress text selection so a drag across a thumbnail doesn't
43 * highlight paragraphs inside the title bar / native body. */
44 user-select: none;
45 -webkit-user-select: none;
46 }
47
48 /*
49 * While in overview, treat each window as a single click target —
50 * every inner element (title bar, buttons, iframe, native body) goes
51 * transparent to pointer events so drags/taps never start a drag,
52 * trip a close button, or launch an in-iframe action. Only the
53 * window's root element receives pointer events; our desktop-level
54 * pointerdown/pointerup handlers drive selection from there.
55 */
56 .os-window--overview * {
57 pointer-events: none;
58 }
59
60 .os-window--overview {
61 pointer-events: auto;
62 }
63
64 .os-window--overview:hover {
65 box-shadow:
66 0 14px 38px rgba( 0, 0, 0, 0.45 ),
67 0 0 0 3px var( --wp-admin-theme-color, #2271b1 );
68 z-index: 1;
69 }
70
71 /*
72 * Minimized windows shown in overview are rendered slightly dimmed
73 * so the user can distinguish them from active windows at a glance.
74 */
75 .os-window--overview.os-window--minimized {
76 opacity: 0.6;
77 }
78
79 /*
80 * Mission-Control-style dimming: once ANY window is hovered, every
81 * OTHER window dims and desaturates slightly — creating a clear
82 * focal point without needing the hovered one to grow or lift.
83 * `:has()` lands in every evergreen browser we target (Chrome 105,
84 * Safari 15.4, Firefox 121+); older engines miss the dimming but
85 * keep the accent-ring affordance, so it degrades gracefully.
86 */
87 .os-area--overview:has( .os-window--overview:hover )
88 .os-window--overview:not( :hover ) {
89 opacity: 0.5;
90 filter: brightness( 0.75 );
91 transition:
92 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
93 opacity 0.18s ease,
94 filter 0.18s ease;
95 }
96
97 /*
98 * Dock slides out smoothly during overview — width collapses (the
99 * flex row reflows so the area grows into the freed space) while
100 * the dock itself slides left and fades. `display: none` would have
101 * been abrupt in both directions; animating the flex width does the
102 * heavy lifting and the user sees a single continuous motion.
103 *
104 * `pointer-events: none` comes in immediately on overview enter so
105 * stray clicks mid-animation can't open a window behind the user's
106 * back. `overflow: hidden` is scoped to the collapsed state so the
107 * shrinking dock doesn't leak icons past its boundary — outside
108 * overview, the dock keeps `overflow: visible` from dock.css so
109 * per-tile "+ open another" chips can float past the edge.
110 */
111 .os-dock {
112 transition:
113 width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
114 min-width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
115 padding 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
116 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
117 opacity 0.22s ease;
118 }
119
120 /*
121 * The escape hatch for the rule above, and the reason it lives here
122 * rather than in `dock.css`: this is the only place `.os-dock` is
123 * given a transition, so it is the only place worth looking when one
124 * fires where it should not.
125 *
126 * The properties above are geometry, and geometry also changes for a
127 * reason that is not a state change: moving the dock to another edge
128 * tears the rail down and builds a new one on the SAME element, which
129 * still carries the previous placement's padding and width. Animated,
130 * the new dock slides out of the old one's shape — it arrives a size
131 * too big and settles. `Dock`'s constructor wears this class while it
132 * commits the placement, so that change lands with nothing to tween
133 * from.
134 */
135 .os-dock--no-transition {
136 transition: none !important;
137 }
138
139 /*
140 * Collapse EVERY dock (bottom + side rails, Classic / Unified /
141 * Spatial layouts alike) when overview is active.
142 *
143 * The placement-specific width rules in dock.css —
144 * `.os-dock[ data-os-dock-placement="left" ]
145 * { width: var( --os-dock-width ); }` — share equal
146 * specificity with `.os-shell--overview .os-dock`
147 * (two classes / class+attr) and load LATER in the cascade, so
148 * without `!important` the side rail keeps its placement width
149 * and stays visible during overview. The bottom dock happens to
150 * lack a placement-attr-keyed width override so it collapsed
151 * fine; the side rail did not — caught by the regression
152 * screenshot.
153 *
154 * `!important` is the right tool here: this rule is a transient,
155 * mode-scoped override (overview screen only) of a layout-mode
156 * default, and we want it to win unconditionally.
157 */
158 .os-shell--overview .os-dock,
159 .os-shell--overview #os-side-dock {
160 width: 0 !important;
161 min-width: 0 !important;
162 padding-inline: 0 !important;
163 padding-block: 0 !important;
164 transform: translateX( -16px );
165 opacity: 0;
166 overflow: hidden;
167 pointer-events: none;
168 transition:
169 width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
170 min-width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
171 padding 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
172 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
173 opacity 0.22s ease;
174 }
175
176 @media ( prefers-reduced-motion: reduce ) {
177 .os-dock {
178 transition-duration: 0.01ms;
179 }
180 }
181
182 /*
183 * Desktop shortcut icons & files-layer tiles —
184 * hidden during overview so they don't compete with window
185 * thumbnails or overlap them (especially noticeable with few
186 * windows or Spatial layout). Matches the fade-out pattern
187 * used by widgets and pinned notes. Scoped to DIRECT children
188 * of the desktop area only: folder windows mount their own
189 * files layer inside the window body, and that must stay
190 * visible in its thumbnail.
191 */
192 .os-area--overview > .os-icons,
193 .os-area--overview > .os-files-layer {
194 opacity: 0;
195 pointer-events: none;
196 transition: opacity 0.22s ease;
197 }
198
199 /* ---------------------------------------------------------------
200 * Overview thumbnail labels.
201 *
202 * Sit outside each window's transform (as absolute-positioned
203 * siblings in the desktop area) so they stay readable at any
204 * thumbnail scale — an icon-sized thumbnail still has its
205 * full-size caption hovering above it.
206 *
207 * Layout: one line, icon + title (+ optional meta). Horizontal
208 * center-of-thumbnail alignment is handled via the label's
209 * own flex + width set in JS to match the scaled thumbnail.
210 * --------------------------------------------------------------- */
211 .os-overview-label {
212 position: absolute;
213 height: 28px;
214 display: flex;
215 align-items: center;
216 justify-content: center;
217 gap: 6px;
218 padding: 0 10px;
219 color: var( --os-ui-fg-on-accent, #fff );
220 font-size: 13px;
221 font-weight: 500;
222 line-height: 1;
223 letter-spacing: 0.01em;
224 text-shadow: 0 1px 3px rgba( 0, 0, 0, 0.55 );
225 white-space: nowrap;
226 pointer-events: none;
227 opacity: 0;
228 transform: translateY( 4px );
229 transition:
230 opacity 0.22s ease 0.06s,
231 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ) 0.06s;
232 z-index: 2;
233 }
234
235 /*
236 * Active labels fade/slide in once the area enters overview mode.
237 * The short delay on `transition-*` lets the thumbnails start
238 * moving first, so labels appear to "catch up" rather than race
239 * ahead of their windows.
240 */
241 .os-area--overview .os-overview-label {
242 opacity: 1;
243 transform: translateY( 0 );
244 }
245
246 /* On exit, flip the animation off. */
247 .os-overview-label--out {
248 opacity: 0 !important;
249 transform: translateY( -4px ) !important;
250 transition-delay: 0s !important;
251 }
252
253 .os-overview-label__icon {
254 font-size: 16px;
255 width: 16px;
256 height: 16px;
257 line-height: 1;
258 flex-shrink: 0;
259 opacity: 0.9;
260 }
261
262 .os-overview-label__title {
263 overflow: hidden;
264 text-overflow: ellipsis;
265 }
266
267 .os-overview-label__meta {
268 color: rgba( 255, 255, 255, 0.7 );
269 font-weight: 400;
270 flex-shrink: 0;
271 }
272
273 /*
274 * Dim labels when another window is hovered. DOM order places
275 * each label immediately after its window, so the adjacent-
276 * sibling selector picks out exactly the label belonging to the
277 * hovered window and keeps it bright; all other labels fall under
278 * the `:has()` rule and dim.
279 */
280 .os-area--overview:has( .os-window--overview:hover )
281 .os-overview-label {
282 opacity: 0.45;
283 transform: translateY( 0 );
284 }
285
286 .os-window--overview:hover + .os-overview-label {
287 opacity: 1 !important;
288 }
289
290 @media ( prefers-reduced-motion: reduce ) {
291 .os-overview-label {
292 transition-duration: 0.01ms;
293 transition-delay: 0s;
294 }
295 }
296
297 /*
298 * Focused-window label overlay is not strictly needed — the title
299 * bar stays visible in the scaled thumbnail. If we later want a
300 * cleaner label (to combat tiny text on 8+-window grids), slot it
301 * in here via a ::after pseudo-element.
302 */
303
304 @media ( prefers-reduced-motion: reduce ) {
305 .os-area--overview,
306 .os-window--overview {
307 transition-duration: 0.01ms;
308 }
309 .os-area--overview > .os-icons,
310 .os-area--overview > .os-files-layer {
311 transition-duration: 0.01ms;
312 }
313 }
314
315 /* ---------------------------------------------------------------
316 * Overview top bar — virtual desktops ("Spaces") strip.
317 *
318 * Lives at the top of the desktop area while overview is active,
319 * stacked above the dimmed backdrop and below the window
320 * thumbnails. Each tile represents one desktop; clicking switches
321 * to it (and exits overview), the trailing "+" tile creates a new
322 * one, and per-tile X buttons close.
323 * --------------------------------------------------------------- */
324
325 .os-overview-top-bar {
326 position: absolute;
327 top: 16px;
328 left: 50%;
329 transform: translateX( -50% );
330 z-index: 2;
331 opacity: 0;
332 pointer-events: none;
333 transition:
334 opacity 0.22s ease 0.06s,
335 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ) 0.06s;
336 }
337
338 .os-area--overview .os-overview-top-bar {
339 opacity: 1;
340 pointer-events: auto;
341 }
342
343 .os-overview-top-bar--out {
344 opacity: 0 !important;
345 transform: translateX( -50% ) translateY( -6px ) !important;
346 transition-delay: 0s !important;
347 }
348
349 .os-overview-top-bar__list {
350 display: flex;
351 flex-direction: row;
352 align-items: stretch;
353 gap: 12px;
354 padding: 8px 12px;
355 border-radius: 14px;
356 background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.32 ) );
357 backdrop-filter: blur( 18px ) saturate( 140% );
358 -webkit-backdrop-filter: blur( 18px ) saturate( 140% );
359 box-shadow:
360 0 8px 28px rgba( 0, 0, 0, 0.35 ),
361 inset 0 0 0 1px rgba( 255, 255, 255, 0.08 );
362 }
363
364 .os-overview-top-bar__tile {
365 position: relative;
366 display: flex;
367 flex-direction: column;
368 align-items: stretch;
369 justify-content: stretch;
370 width: 140px;
371 padding: 0;
372 margin: 0;
373 background: rgba( 255, 255, 255, 0.04 );
374 border: 2px solid rgba( 255, 255, 255, 0.18 );
375 border-radius: 10px;
376 color: var( --os-ui-fg-on-accent, #fff );
377 cursor: pointer;
378 overflow: hidden;
379 transition:
380 border-color 0.18s ease,
381 background-color 0.18s ease,
382 transform 0.18s ease;
383 font: inherit;
384 }
385
386 .os-overview-top-bar__tile:hover {
387 border-color: rgba( 255, 255, 255, 0.4 );
388 background: rgba( 255, 255, 255, 0.08 );
389 }
390
391 .os-overview-top-bar__tile:focus-visible {
392 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
393 outline-offset: 2px;
394 }
395
396 .os-overview-top-bar__tile--active {
397 border-color: var( --wp-admin-theme-color, #2271b1 );
398 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
399 }
400
401 .os-overview-top-bar__tile-preview {
402 display: flex;
403 align-items: center;
404 justify-content: center;
405 height: 60px;
406 background: linear-gradient(
407 135deg,
408 rgba( 255, 255, 255, 0.04 ),
409 rgba( 255, 255, 255, 0.12 )
410 );
411 border-bottom: 1px solid rgba( 255, 255, 255, 0.08 );
412 }
413
414 .os-overview-top-bar__tile-count {
415 font-size: 18px;
416 font-weight: 600;
417 color: rgba( 255, 255, 255, 0.7 );
418 letter-spacing: 0.02em;
419 }
420
421 .os-overview-top-bar__tile-label {
422 display: block;
423 padding: 6px 10px 8px;
424 text-align: center;
425 font-size: 12px;
426 font-weight: 500;
427 color: rgba( 255, 255, 255, 0.85 );
428 white-space: nowrap;
429 overflow: hidden;
430 text-overflow: ellipsis;
431 }
432
433 .os-overview-top-bar__tile-wrapper {
434 position: relative;
435 display: inline-block;
436 }
437
438 .os-overview-top-bar__tile-close {
439 position: absolute;
440 top: 4px;
441 inset-inline-end: 4px;
442 width: 18px;
443 height: 18px;
444 display: flex;
445 align-items: center;
446 justify-content: center;
447 color: rgba( 255, 255, 255, 0.7 );
448 background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) );
449 border-radius: 50%;
450 cursor: pointer;
451 opacity: 0;
452 transition:
453 opacity 0.15s ease,
454 background-color 0.15s ease,
455 color 0.15s ease;
456 border: none;
457 padding: 0;
458 }
459
460 .os-overview-top-bar__tile-wrapper:hover
461 .os-overview-top-bar__tile-close,
462 .os-overview-top-bar__tile-wrapper:focus-within
463 .os-overview-top-bar__tile-close,
464 .os-overview-top-bar__tile-close:focus-visible {
465 opacity: 1;
466 }
467
468 .os-overview-top-bar__tile-close:hover {
469 background: var( --os-ui-danger, #d63638 );
470 color: var( --os-ui-fg-on-accent, #fff );
471 }
472
473 /*
474 * Hide the close X when there's only one tile left — the tile
475 * list contains both desktop wrappers AND the trailing "+".
476 * So "only one desktop" means exactly one wrapper in the list.
477 */
478 .os-overview-top-bar__list:has(
479 .os-overview-top-bar__tile-wrapper:only-of-type
480 )
481 .os-overview-top-bar__tile-close {
482 display: none;
483 }
484
485 .os-overview-top-bar__tile--add {
486 width: 60px;
487 background: transparent;
488 border-style: dashed;
489 }
490
491 .os-overview-top-bar__tile--add:hover {
492 background: rgba( 255, 255, 255, 0.08 );
493 }
494
495 /*
496 * Keyboard cursor parked on the "+" tile. Mirrors the visual weight
497 * of `--active` (solid accent border + halo) so the user sees at a
498 * glance "Enter will land here". The dashed border on the add tile
499 * flips to solid when the cursor lands, matching the desktop tiles'
500 * solid borders.
501 */
502 .os-overview-top-bar__tile--add.os-overview-top-bar__tile--cursor {
503 border-style: solid;
504 border-color: var( --wp-admin-theme-color, #2271b1 );
505 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
506 background: rgba( 255, 255, 255, 0.08 );
507 }
508
509 .os-overview-top-bar__tile-plus {
510 display: flex;
511 align-items: center;
512 justify-content: center;
513 flex: 1;
514 font-size: 28px;
515 font-weight: 200;
516 color: rgba( 255, 255, 255, 0.7 );
517 line-height: 1;
518 }
519
520 @media ( prefers-reduced-motion: reduce ) {
521 .os-overview-top-bar {
522 transition-duration: 0.01ms;
523 }
524 }
525