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

506 lines 14.2 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 * Collapse EVERY dock (bottom + side rails, Classic / Unified /
122 * Spatial layouts alike) when overview is active.
123 *
124 * The placement-specific width rules in dock.css —
125 * `.os-dock[ data-os-dock-placement="left" ]
126 * { width: var( --os-dock-width ); }` — share equal
127 * specificity with `.os-shell--overview .os-dock`
128 * (two classes / class+attr) and load LATER in the cascade, so
129 * without `!important` the side rail keeps its placement width
130 * and stays visible during overview. The bottom dock happens to
131 * lack a placement-attr-keyed width override so it collapsed
132 * fine; the side rail did not — caught by the regression
133 * screenshot.
134 *
135 * `!important` is the right tool here: this rule is a transient,
136 * mode-scoped override (overview screen only) of a layout-mode
137 * default, and we want it to win unconditionally.
138 */
139 .os-shell--overview .os-dock,
140 .os-shell--overview #os-side-dock {
141 width: 0 !important;
142 min-width: 0 !important;
143 padding-inline: 0 !important;
144 padding-block: 0 !important;
145 transform: translateX( -16px );
146 opacity: 0;
147 overflow: hidden;
148 pointer-events: none;
149 transition:
150 width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
151 min-width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
152 padding 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
153 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
154 opacity 0.22s ease;
155 }
156
157 @media ( prefers-reduced-motion: reduce ) {
158 .os-dock {
159 transition-duration: 0.01ms;
160 }
161 }
162
163 /*
164 * Desktop shortcut icons & files-layer tiles —
165 * hidden during overview so they don't compete with window
166 * thumbnails or overlap them (especially noticeable with few
167 * windows or Spatial layout). Matches the fade-out pattern
168 * used by widgets and sticky notes. Scoped to DIRECT children
169 * of the desktop area only: folder windows mount their own
170 * files layer inside the window body, and that must stay
171 * visible in its thumbnail.
172 */
173 .os-area--overview > .os-icons,
174 .os-area--overview > .os-files-layer {
175 opacity: 0;
176 pointer-events: none;
177 transition: opacity 0.22s ease;
178 }
179
180 /* ---------------------------------------------------------------
181 * Overview thumbnail labels.
182 *
183 * Sit outside each window's transform (as absolute-positioned
184 * siblings in the desktop area) so they stay readable at any
185 * thumbnail scale — an icon-sized thumbnail still has its
186 * full-size caption hovering above it.
187 *
188 * Layout: one line, icon + title (+ optional meta). Horizontal
189 * center-of-thumbnail alignment is handled via the label's
190 * own flex + width set in JS to match the scaled thumbnail.
191 * --------------------------------------------------------------- */
192 .os-overview-label {
193 position: absolute;
194 height: 28px;
195 display: flex;
196 align-items: center;
197 justify-content: center;
198 gap: 6px;
199 padding: 0 10px;
200 color: var( --os-ui-fg-on-accent, #fff );
201 font-size: 13px;
202 font-weight: 500;
203 line-height: 1;
204 letter-spacing: 0.01em;
205 text-shadow: 0 1px 3px rgba( 0, 0, 0, 0.55 );
206 white-space: nowrap;
207 pointer-events: none;
208 opacity: 0;
209 transform: translateY( 4px );
210 transition:
211 opacity 0.22s ease 0.06s,
212 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ) 0.06s;
213 z-index: 2;
214 }
215
216 /*
217 * Active labels fade/slide in once the area enters overview mode.
218 * The short delay on `transition-*` lets the thumbnails start
219 * moving first, so labels appear to "catch up" rather than race
220 * ahead of their windows.
221 */
222 .os-area--overview .os-overview-label {
223 opacity: 1;
224 transform: translateY( 0 );
225 }
226
227 /* On exit, flip the animation off. */
228 .os-overview-label--out {
229 opacity: 0 !important;
230 transform: translateY( -4px ) !important;
231 transition-delay: 0s !important;
232 }
233
234 .os-overview-label__icon {
235 font-size: 16px;
236 width: 16px;
237 height: 16px;
238 line-height: 1;
239 flex-shrink: 0;
240 opacity: 0.9;
241 }
242
243 .os-overview-label__title {
244 overflow: hidden;
245 text-overflow: ellipsis;
246 }
247
248 .os-overview-label__meta {
249 color: rgba( 255, 255, 255, 0.7 );
250 font-weight: 400;
251 flex-shrink: 0;
252 }
253
254 /*
255 * Dim labels when another window is hovered. DOM order places
256 * each label immediately after its window, so the adjacent-
257 * sibling selector picks out exactly the label belonging to the
258 * hovered window and keeps it bright; all other labels fall under
259 * the `:has()` rule and dim.
260 */
261 .os-area--overview:has( .os-window--overview:hover )
262 .os-overview-label {
263 opacity: 0.45;
264 transform: translateY( 0 );
265 }
266
267 .os-window--overview:hover + .os-overview-label {
268 opacity: 1 !important;
269 }
270
271 @media ( prefers-reduced-motion: reduce ) {
272 .os-overview-label {
273 transition-duration: 0.01ms;
274 transition-delay: 0s;
275 }
276 }
277
278 /*
279 * Focused-window label overlay is not strictly needed — the title
280 * bar stays visible in the scaled thumbnail. If we later want a
281 * cleaner label (to combat tiny text on 8+-window grids), slot it
282 * in here via a ::after pseudo-element.
283 */
284
285 @media ( prefers-reduced-motion: reduce ) {
286 .os-area--overview,
287 .os-window--overview {
288 transition-duration: 0.01ms;
289 }
290 .os-area--overview > .os-icons,
291 .os-area--overview > .os-files-layer {
292 transition-duration: 0.01ms;
293 }
294 }
295
296 /* ---------------------------------------------------------------
297 * Overview top bar — virtual desktops ("Spaces") strip.
298 *
299 * Lives at the top of the desktop area while overview is active,
300 * stacked above the dimmed backdrop and below the window
301 * thumbnails. Each tile represents one desktop; clicking switches
302 * to it (and exits overview), the trailing "+" tile creates a new
303 * one, and per-tile X buttons close.
304 * --------------------------------------------------------------- */
305
306 .os-overview-top-bar {
307 position: absolute;
308 top: 16px;
309 left: 50%;
310 transform: translateX( -50% );
311 z-index: 2;
312 opacity: 0;
313 pointer-events: none;
314 transition:
315 opacity 0.22s ease 0.06s,
316 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ) 0.06s;
317 }
318
319 .os-area--overview .os-overview-top-bar {
320 opacity: 1;
321 pointer-events: auto;
322 }
323
324 .os-overview-top-bar--out {
325 opacity: 0 !important;
326 transform: translateX( -50% ) translateY( -6px ) !important;
327 transition-delay: 0s !important;
328 }
329
330 .os-overview-top-bar__list {
331 display: flex;
332 flex-direction: row;
333 align-items: stretch;
334 gap: 12px;
335 padding: 8px 12px;
336 border-radius: 14px;
337 background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.32 ) );
338 backdrop-filter: blur( 18px ) saturate( 140% );
339 -webkit-backdrop-filter: blur( 18px ) saturate( 140% );
340 box-shadow:
341 0 8px 28px rgba( 0, 0, 0, 0.35 ),
342 inset 0 0 0 1px rgba( 255, 255, 255, 0.08 );
343 }
344
345 .os-overview-top-bar__tile {
346 position: relative;
347 display: flex;
348 flex-direction: column;
349 align-items: stretch;
350 justify-content: stretch;
351 width: 140px;
352 padding: 0;
353 margin: 0;
354 background: rgba( 255, 255, 255, 0.04 );
355 border: 2px solid rgba( 255, 255, 255, 0.18 );
356 border-radius: 10px;
357 color: var( --os-ui-fg-on-accent, #fff );
358 cursor: pointer;
359 overflow: hidden;
360 transition:
361 border-color 0.18s ease,
362 background-color 0.18s ease,
363 transform 0.18s ease;
364 font: inherit;
365 }
366
367 .os-overview-top-bar__tile:hover {
368 border-color: rgba( 255, 255, 255, 0.4 );
369 background: rgba( 255, 255, 255, 0.08 );
370 }
371
372 .os-overview-top-bar__tile:focus-visible {
373 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
374 outline-offset: 2px;
375 }
376
377 .os-overview-top-bar__tile--active {
378 border-color: var( --wp-admin-theme-color, #2271b1 );
379 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
380 }
381
382 .os-overview-top-bar__tile-preview {
383 display: flex;
384 align-items: center;
385 justify-content: center;
386 height: 60px;
387 background: linear-gradient(
388 135deg,
389 rgba( 255, 255, 255, 0.04 ),
390 rgba( 255, 255, 255, 0.12 )
391 );
392 border-bottom: 1px solid rgba( 255, 255, 255, 0.08 );
393 }
394
395 .os-overview-top-bar__tile-count {
396 font-size: 18px;
397 font-weight: 600;
398 color: rgba( 255, 255, 255, 0.7 );
399 letter-spacing: 0.02em;
400 }
401
402 .os-overview-top-bar__tile-label {
403 display: block;
404 padding: 6px 10px 8px;
405 text-align: center;
406 font-size: 12px;
407 font-weight: 500;
408 color: rgba( 255, 255, 255, 0.85 );
409 white-space: nowrap;
410 overflow: hidden;
411 text-overflow: ellipsis;
412 }
413
414 .os-overview-top-bar__tile-wrapper {
415 position: relative;
416 display: inline-block;
417 }
418
419 .os-overview-top-bar__tile-close {
420 position: absolute;
421 top: 4px;
422 inset-inline-end: 4px;
423 width: 18px;
424 height: 18px;
425 display: flex;
426 align-items: center;
427 justify-content: center;
428 color: rgba( 255, 255, 255, 0.7 );
429 background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) );
430 border-radius: 50%;
431 cursor: pointer;
432 opacity: 0;
433 transition:
434 opacity 0.15s ease,
435 background-color 0.15s ease,
436 color 0.15s ease;
437 border: none;
438 padding: 0;
439 }
440
441 .os-overview-top-bar__tile-wrapper:hover
442 .os-overview-top-bar__tile-close,
443 .os-overview-top-bar__tile-wrapper:focus-within
444 .os-overview-top-bar__tile-close,
445 .os-overview-top-bar__tile-close:focus-visible {
446 opacity: 1;
447 }
448
449 .os-overview-top-bar__tile-close:hover {
450 background: var( --os-ui-danger, #d63638 );
451 color: var( --os-ui-fg-on-accent, #fff );
452 }
453
454 /*
455 * Hide the close X when there's only one tile left — the tile
456 * list contains both desktop wrappers AND the trailing "+".
457 * So "only one desktop" means exactly one wrapper in the list.
458 */
459 .os-overview-top-bar__list:has(
460 .os-overview-top-bar__tile-wrapper:only-of-type
461 )
462 .os-overview-top-bar__tile-close {
463 display: none;
464 }
465
466 .os-overview-top-bar__tile--add {
467 width: 60px;
468 background: transparent;
469 border-style: dashed;
470 }
471
472 .os-overview-top-bar__tile--add:hover {
473 background: rgba( 255, 255, 255, 0.08 );
474 }
475
476 /*
477 * Keyboard cursor parked on the "+" tile. Mirrors the visual weight
478 * of `--active` (solid accent border + halo) so the user sees at a
479 * glance "Enter will land here". The dashed border on the add tile
480 * flips to solid when the cursor lands, matching the desktop tiles'
481 * solid borders.
482 */
483 .os-overview-top-bar__tile--add.os-overview-top-bar__tile--cursor {
484 border-style: solid;
485 border-color: var( --wp-admin-theme-color, #2271b1 );
486 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
487 background: rgba( 255, 255, 255, 0.08 );
488 }
489
490 .os-overview-top-bar__tile-plus {
491 display: flex;
492 align-items: center;
493 justify-content: center;
494 flex: 1;
495 font-size: 28px;
496 font-weight: 200;
497 color: rgba( 255, 255, 255, 0.7 );
498 line-height: 1;
499 }
500
501 @media ( prefers-reduced-motion: reduce ) {
502 .os-overview-top-bar {
503 transition-duration: 0.01ms;
504 }
505 }
506