PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.7
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.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 / dock-peek.css

dock-peek.css in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.7, at assets/css/dock-peek.css

633 lines 20.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Desktop Mode — Dock Peek.
3 *
4 * Hover-reveal popover that fans out from a multi-instance dock tile.
5 * Each card is styled as a miniature window — faux titlebar with
6 * traffic-light dots + the page icon + the live window title, tinted
7 * body with ghosted content lines. The trailing Ghost Card matches
8 * the geometry but is dashed + breathing to announce itself as the
9 * "open new" affordance.
10 *
11 * Click an instance card → `document.startViewTransition()` morphs
12 * it into the focused window. Click the Ghost Card → same API
13 * morphs it into the freshly-spawned window.
14 *
15 * Three motion layers:
16 * 1. Tile lift — the dock icon springs up + magnifies on hover.
17 * 2. Card fan-out — cards slide in staggered, with a subtle peel.
18 * 3. Ghost pulse — the trailing card breathes until hovered.
19 *
20 * @since 0.6.2
21 */
22
23 /* ──────────────────────────────────────────────────────────────────
24 Tile lift — applied to ANY dock tile on hover. Cheap and additive
25 to the existing dock styles; doesn't depend on the peek being
26 present (the icon should feel responsive even when there's no
27 peek to show).
28 ────────────────────────────────────────────────────────────────── */
29
30 .desktop-mode-dock__item-primary {
31 transition:
32 transform 240ms cubic-bezier( 0.34, 1.56, 0.64, 1 ),
33 filter 240ms ease-out;
34 }
35
36 .desktop-mode-dock__item:hover .desktop-mode-dock__item-primary,
37 .desktop-mode-dock__item[data-peek-active] .desktop-mode-dock__item-primary {
38 background: rgba( 255, 255, 255, 0.15 );
39 color: #fff;
40 transform: scale( 1.08 );
41 filter: drop-shadow( 0 4px 8px rgba( 0, 0, 0, 0.18 ) );
42 }
43
44 @media ( prefers-reduced-motion: reduce ) {
45 .desktop-mode-dock__item-primary,
46 .desktop-mode-dock__item:hover .desktop-mode-dock__item-primary,
47 .desktop-mode-dock__item[data-peek-active] .desktop-mode-dock__item-primary {
48 transition: none;
49 transform: none;
50 }
51 }
52
53 /* ──────────────────────────────────────────────────────────────────
54 Popover surface — glass material, body-attached.
55 ────────────────────────────────────────────────────────────────── */
56
57 .desktop-mode-dock-peek {
58 position: fixed;
59 z-index: 999999;
60 padding: 10px;
61 border-radius: 16px;
62 background: color-mix( in srgb, var( --desktop-mode-bg, #1d2327 ) 76%, transparent );
63 backdrop-filter: blur( 28px ) saturate( 180% );
64 -webkit-backdrop-filter: blur( 28px ) saturate( 180% );
65 border: 1px solid rgba( 255, 255, 255, 0.12 );
66 box-shadow:
67 0 1px 0 rgba( 255, 255, 255, 0.08 ) inset,
68 0 16px 40px -10px rgba( 0, 0, 0, 0.55 ),
69 0 6px 16px -4px rgba( 0, 0, 0, 0.36 );
70 color: var( --desktop-mode-fg, #fff );
71 pointer-events: auto;
72 opacity: 0;
73 display: flex;
74 flex-direction: column;
75 transition: opacity 160ms ease-out;
76 /* Default (left/right docks) — vertical column. The popover caps
77 in height; cards scroll inside. */
78 max-height: min( 80vh, 480px );
79 max-width: min( 90vw, 320px );
80 }
81
82 /* Bottom-dock orientation: cards form a horizontal reel. The popover
83 caps in WIDTH instead of height, and the cards container scrolls
84 horizontally. Visually mirrors how taskbar-style docks work — a
85 row of mini-windows above the icon, not a stack. */
86 .desktop-mode-dock-peek[ data-orientation = "bottom" ] {
87 max-height: none;
88 max-width: min( 92vw, 920px );
89 }
90
91 .desktop-mode-dock-peek--open {
92 opacity: 1;
93 }
94
95 /* Anchor flips by orientation. The popover's anchor point (the
96 coordinate set in JS) sits ON the tile edge; we translate from
97 there so the popover floats off-edge with a gap. The
98 `--peek-clamp-x/y` props are added by JS when the popover would
99 otherwise overflow the viewport — they nudge it inward without
100 losing the orientation translate. */
101 .desktop-mode-dock-peek[ data-orientation = "left" ] {
102 transform:
103 translate(
104 var( --peek-clamp-x, 0 ),
105 calc( -50% + var( --peek-clamp-y, 0px ) )
106 );
107 }
108 .desktop-mode-dock-peek[ data-orientation = "right" ] {
109 transform:
110 translate(
111 calc( -100% + var( --peek-clamp-x, 0px ) ),
112 calc( -50% + var( --peek-clamp-y, 0px ) )
113 );
114 }
115 .desktop-mode-dock-peek[ data-orientation = "bottom" ] {
116 transform:
117 translate(
118 calc( -50% + var( --peek-clamp-x, 0px ) ),
119 calc( -100% + var( --peek-clamp-y, 0px ) )
120 );
121 }
122
123 /* ──────────────────────────────────────────────────────────────────
124 Cards.
125 ────────────────────────────────────────────────────────────────── */
126
127 .desktop-mode-dock-peek__cards {
128 display: flex;
129 flex-direction: column;
130 gap: 8px;
131 min-width: 280px;
132 /* Take up whatever vertical space the popover offers and scroll
133 internally once the cards spill beyond it. Subtract the
134 popover's padding so the scrollbar doesn't flush against the
135 rounded outer edge. */
136 flex: 1 1 auto;
137 min-height: 0;
138 overflow-y: auto;
139 overflow-x: hidden;
140 /* Hide the scrollbar visually until hover — the peek surface is
141 meant to feel weightless, not "yet another panel with a
142 scrollbar." Falls back to the platform scrollbar where the
143 custom-scrollbar pseudo isn't supported. */
144 scrollbar-width: thin;
145 scrollbar-color: rgba( 255, 255, 255, 0.18 ) transparent;
146 }
147
148 /* Bottom dock: cards lay out as a horizontal reel and scroll on the
149 X-axis instead of Y. */
150 .desktop-mode-dock-peek[ data-orientation = "bottom" ] .desktop-mode-dock-peek__cards {
151 flex-direction: row;
152 min-width: 0;
153 overflow-x: auto;
154 overflow-y: hidden;
155 max-width: 100%;
156 }
157
158 .desktop-mode-dock-peek[ data-orientation = "bottom" ] .desktop-mode-dock-peek__card {
159 /* Bottom-dock cards are narrower than left/right dock cards —
160 a horizontal reel reads better with thumbnail-shaped tiles
161 (Mission Control / Stage Manager) than with full-width
162 sidebar-shaped ones. flex: 0 0 auto so a long reel doesn't
163 squish each card down to nothing. */
164 flex: 0 0 auto;
165 width: 200px;
166 min-height: 116px;
167 /* Cards translate from BELOW into the reel (towards the dock
168 tile they peeled off of), so the directional motion still
169 points back at the icon. */
170 transform: translateY( 10px ) scale( 0.96 );
171 }
172
173 .desktop-mode-dock-peek[ data-orientation = "bottom" ] .desktop-mode-dock-peek__card--ghost {
174 width: 200px;
175 min-height: 116px;
176 }
177
178 .desktop-mode-dock-peek[ data-orientation = "bottom" ].desktop-mode-dock-peek--open
179 .desktop-mode-dock-peek__card {
180 transform: translateY( 0 ) scale( 1 );
181 }
182
183 .desktop-mode-dock-peek__cards::-webkit-scrollbar {
184 width: 8px;
185 height: 8px;
186 }
187 .desktop-mode-dock-peek__cards::-webkit-scrollbar-track {
188 background: transparent;
189 }
190 .desktop-mode-dock-peek__cards::-webkit-scrollbar-thumb {
191 background: rgba( 255, 255, 255, 0.18 );
192 border-radius: 8px;
193 border: 2px solid transparent;
194 background-clip: padding-box;
195 }
196 .desktop-mode-dock-peek__cards::-webkit-scrollbar-thumb:hover {
197 background: rgba( 255, 255, 255, 0.32 );
198 background-clip: padding-box;
199 }
200
201 .desktop-mode-dock-peek__card {
202 /* Card frame — looks like a tiny window. */
203 display: flex;
204 flex-direction: column;
205 overflow: hidden;
206 width: 280px;
207 min-height: 92px;
208 padding: 0;
209 border: 1px solid rgba( 255, 255, 255, 0.10 );
210 border-radius: 10px;
211 background: rgba( 255, 255, 255, 0.04 );
212 color: inherit;
213 font: inherit;
214 text-align: start;
215 cursor: pointer;
216 view-transition-name: var( --peek-card-vt-name, none );
217 /* Animation start state — cards begin slightly displaced toward
218 the tile they "peeled off of". CSS resets to identity once the
219 `--open` class on the parent triggers the transition. */
220 opacity: 0;
221 transform: translateX( -10px ) scale( 0.96 );
222 transition:
223 opacity 240ms ease-out var( --peek-card-delay, 0ms ),
224 transform 320ms cubic-bezier( 0.34, 1.56, 0.64, 1 ) var( --peek-card-delay, 0ms ),
225 border-color 180ms ease-out,
226 box-shadow 180ms ease-out;
227 }
228
229 .desktop-mode-dock-peek--open .desktop-mode-dock-peek__card {
230 opacity: 1;
231 transform: translateX( 0 ) scale( 1 );
232 }
233
234 .desktop-mode-dock-peek__card:hover {
235 border-color: rgba( 255, 255, 255, 0.24 );
236 box-shadow: 0 4px 14px -4px rgba( 0, 0, 0, 0.4 );
237 }
238
239 .desktop-mode-dock-peek__card:focus-visible {
240 outline: 2px solid var( --desktop-mode-accent, #2271b1 );
241 outline-offset: 2px;
242 }
243
244 /* ──────────────────────────────────────────────────────────────────
245 Mini-window chrome — instance card faux titlebar.
246 ────────────────────────────────────────────────────────────────── */
247
248 .desktop-mode-dock-peek__card-titlebar {
249 display: flex;
250 align-items: center;
251 gap: 8px;
252 padding: 8px 10px;
253 /* Use the live window's titlebar background so the mini-window
254 reads as a faithful shrink of the real window. Falls back to a
255 neutral translucent gradient when the variable isn't set (early
256 load, theme without the token, tests). */
257 background: var(
258 --desktop-mode-titlebar-bg-focused,
259 linear-gradient(
260 to bottom,
261 rgba( 255, 255, 255, 0.10 ),
262 rgba( 255, 255, 255, 0.04 )
263 )
264 );
265 color: var(
266 --desktop-mode-titlebar-color-focused,
267 var( --desktop-mode-fg, #fff )
268 );
269 border-bottom: 1px solid rgba( 0, 0, 0, 0.12 );
270 font-size: 12px;
271 line-height: 1.2;
272 }
273
274 .desktop-mode-dock-peek__card-dots {
275 display: inline-flex;
276 gap: 4px;
277 flex: 0 0 auto;
278 }
279
280 .desktop-mode-dock-peek__card-dots i {
281 width: 8px;
282 height: 8px;
283 border-radius: 50%;
284 background: rgba( 255, 255, 255, 0.22 );
285 }
286
287 .desktop-mode-dock-peek__card-dots i:nth-child( 1 ) {
288 background: #ff5f57;
289 }
290 .desktop-mode-dock-peek__card-dots i:nth-child( 2 ) {
291 background: #febc2e;
292 }
293 .desktop-mode-dock-peek__card-dots i:nth-child( 3 ) {
294 background: #28c840;
295 }
296
297 .desktop-mode-dock-peek__card-icon {
298 flex: 0 0 auto;
299 width: 14px;
300 height: 14px;
301 font-size: 14px;
302 line-height: 1;
303 opacity: 0.92;
304 }
305
306 .desktop-mode-dock-peek__card-label {
307 flex: 1 1 auto;
308 overflow: hidden;
309 text-overflow: ellipsis;
310 white-space: nowrap;
311 font-weight: 500;
312 }
313
314 /* ──────────────────────────────────────────────────────────────────
315 Mini-window body — tinted by the page hue, ghosted content lines.
316
317 The hue comes from `hashTitleToHue(window.id || title)`, so two
318 instances of the same page (`edit.php` and `edit.php-2`) read as
319 visually distinct without us having to invent unique colors.
320 ────────────────────────────────────────────────────────────────── */
321
322 .desktop-mode-dock-peek__card-body {
323 flex: 1 1 auto;
324 display: flex;
325 flex-direction: column;
326 gap: 6px;
327 padding: 12px 12px 14px;
328 background:
329 linear-gradient(
330 135deg,
331 hsl( var( --peek-card-hue, 210 ) 55% 22% / 0.65 ),
332 hsl( var( --peek-card-hue, 210 ) 55% 14% / 0.5 )
333 );
334 }
335
336 .desktop-mode-dock-peek__card-line {
337 display: block;
338 height: 6px;
339 border-radius: 3px;
340 background: rgba( 255, 255, 255, 0.16 );
341 }
342
343 .desktop-mode-dock-peek__card-line:nth-child( 1 ) {
344 width: 80%;
345 }
346 .desktop-mode-dock-peek__card-line:nth-child( 2 ) {
347 width: 60%;
348 }
349 .desktop-mode-dock-peek__card-line:nth-child( 3 ) {
350 width: 70%;
351 }
352
353 /* Plugin-customized body — drop the default tinted background +
354 ghost-line padding so the plugin's own markup gets a clean canvas.
355 Plugins that want the tinted look back can re-add their own
356 background; otherwise they get a transparent flex container. */
357 .desktop-mode-dock-peek__card-body--custom {
358 background: transparent;
359 padding: 0;
360 gap: 0;
361 }
362
363 /* ──────────────────────────────────────────────────────────────────
364 Built-in renderer: OS Settings.
365
366 A big tinted hero icon + a phrase + a row of three tab-icon
367 chips representing the inner Settings tabs. Tinted with the
368 user's WP profile accent so the card "belongs" to the active
369 color scheme.
370 ────────────────────────────────────────────────────────────────── */
371
372 .desktop-mode-dock-peek__card-body--os-settings {
373 display: flex;
374 flex-direction: column;
375 align-items: center;
376 justify-content: center;
377 gap: 6px;
378 padding: 14px 12px;
379 background: linear-gradient(
380 135deg,
381 color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 65%, #1d2327 ) 0%,
382 color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 35%, #1d2327 ) 100%
383 );
384 color: #fff;
385 }
386
387 .desktop-mode-dock-peek__os-hero {
388 font-size: 32px;
389 width: 32px;
390 height: 32px;
391 line-height: 1;
392 opacity: 0.95;
393 filter: drop-shadow( 0 1px 2px rgba( 0, 0, 0, 0.4 ) );
394 }
395
396 .desktop-mode-dock-peek__os-subtitle {
397 font-size: 11px;
398 font-weight: 500;
399 letter-spacing: 0.04em;
400 text-transform: uppercase;
401 opacity: 0.85;
402 text-shadow: 0 1px 2px rgba( 0, 0, 0, 0.3 );
403 }
404
405 .desktop-mode-dock-peek__os-tabs {
406 display: flex;
407 gap: 6px;
408 margin-top: 2px;
409 }
410
411 .desktop-mode-dock-peek__os-tab {
412 width: 18px;
413 height: 18px;
414 font-size: 13px;
415 line-height: 18px;
416 border-radius: 4px;
417 background: rgba( 255, 255, 255, 0.18 );
418 color: rgba( 255, 255, 255, 0.92 );
419 text-align: center;
420 }
421
422 /* ──────────────────────────────────────────────────────────────────
423 Built-in renderer: Recycle Bin.
424
425 Empty state: a single trash icon, dim. Full state: a stack of
426 three "slips" peeking from behind the icon + a count chip in the
427 corner. The `data-empty` attribute toggles between the two.
428 ────────────────────────────────────────────────────────────────── */
429
430 .desktop-mode-dock-peek__card-body--recycle-bin {
431 display: flex;
432 flex-direction: column;
433 align-items: center;
434 justify-content: center;
435 gap: 8px;
436 padding: 14px 12px;
437 background: linear-gradient(
438 135deg,
439 #3a3f47 0%,
440 #23272b 100%
441 );
442 color: rgba( 255, 255, 255, 0.92 );
443 }
444
445 .desktop-mode-dock-peek__bin-stage {
446 position: relative;
447 width: 44px;
448 height: 44px;
449 display: flex;
450 align-items: center;
451 justify-content: center;
452 }
453
454 .desktop-mode-dock-peek__bin-icon {
455 font-size: 32px;
456 width: 32px;
457 height: 32px;
458 line-height: 1;
459 opacity: 0.95;
460 filter: drop-shadow( 0 1px 2px rgba( 0, 0, 0, 0.4 ) );
461 z-index: 1;
462 }
463
464 .desktop-mode-dock-peek__bin-stack {
465 position: absolute;
466 inset: 0;
467 display: flex;
468 align-items: flex-end;
469 justify-content: center;
470 pointer-events: none;
471 opacity: 0;
472 transition: opacity 200ms ease-out;
473 }
474
475 .desktop-mode-dock-peek__card-body--recycle-bin[ data-empty = "false" ]
476 .desktop-mode-dock-peek__bin-stack {
477 opacity: 1;
478 }
479
480 .desktop-mode-dock-peek__bin-slip {
481 position: absolute;
482 width: 22px;
483 height: 4px;
484 border-radius: 1px;
485 background: rgba( 255, 255, 255, 0.55 );
486 bottom: 6px;
487 }
488
489 .desktop-mode-dock-peek__bin-slip:nth-child( 1 ) {
490 transform: translate( -10px, -16px ) rotate( -8deg );
491 background: rgba( 255, 255, 255, 0.45 );
492 }
493 .desktop-mode-dock-peek__bin-slip:nth-child( 2 ) {
494 transform: translate( 8px, -20px ) rotate( 6deg );
495 background: rgba( 255, 255, 255, 0.5 );
496 }
497 .desktop-mode-dock-peek__bin-slip:nth-child( 3 ) {
498 transform: translate( -2px, -22px ) rotate( -2deg );
499 background: rgba( 255, 255, 255, 0.6 );
500 }
501
502 .desktop-mode-dock-peek__bin-label {
503 font-size: 11px;
504 font-weight: 500;
505 letter-spacing: 0.02em;
506 color: rgba( 255, 255, 255, 0.78 );
507 }
508
509 .desktop-mode-dock-peek__card-body--recycle-bin[ data-empty = "false" ]
510 .desktop-mode-dock-peek__bin-label {
511 color: var( --wp-admin-theme-color, #4f9cff );
512 font-weight: 600;
513 }
514
515 /* ──────────────────────────────────────────────────────────────────
516 Ghost Card — the "open new" affordance.
517
518 Same geometry as instance cards (so the fan reads as one stack)
519 but visually distinct via:
520 * Dashed border (vs solid)
521 * Lower base opacity
522 * Breathing pulse (slow scale + opacity loop)
523 * Centered "+" + label, no faux titlebar / body lines
524 On hover, the dashes resolve to a solid line, the pulse stops,
525 and opacity ramps to full — the card "solidifies" into the same
526 visual weight as an instance card.
527 ────────────────────────────────────────────────────────────────── */
528
529 .desktop-mode-dock-peek__card--ghost {
530 display: flex;
531 align-items: center;
532 justify-content: center;
533 gap: 10px;
534 width: 280px;
535 min-height: 64px;
536 padding: 16px;
537 border-style: dashed;
538 border-color: rgba( 255, 255, 255, 0.34 );
539 /* A self-contained dark translucent fill so the white label
540 reads on light wallpapers / light color schemes too. The
541 popover's parent surface uses `color-mix(--desktop-mode-bg)`,
542 which goes near-white on light themes — without our own
543 backdrop the Ghost Card was white-on-white. */
544 background: rgba( 0, 0, 0, 0.32 );
545 color: #fff;
546 text-shadow: 0 1px 2px rgba( 0, 0, 0, 0.45 );
547 font-size: 13px;
548 font-weight: 500;
549 animation: desktop-mode-dock-peek-breathe 2400ms ease-in-out infinite;
550 }
551
552 .desktop-mode-dock-peek__card--ghost:hover {
553 border-style: solid;
554 border-color: rgba( 255, 255, 255, 0.55 );
555 background: rgba( 0, 0, 0, 0.45 );
556 color: #fff;
557 animation: none;
558 transform: scale( 1.02 );
559 box-shadow: 0 4px 14px -4px rgba( 0, 0, 0, 0.5 );
560 }
561
562 .desktop-mode-dock-peek__card-plus {
563 flex: 0 0 auto;
564 display: inline-flex;
565 align-items: center;
566 justify-content: center;
567 width: 22px;
568 height: 22px;
569 font-size: 22px;
570 line-height: 1;
571 font-weight: 300;
572 /* Slightly more presence than before (was 0.42 alpha). The
573 "+" is the only glyph the user sees in the resting state,
574 so it has to read at a glance even against the breathing
575 pulse's lower-opacity moments. */
576 color: rgba( 255, 255, 255, 0.78 );
577 text-shadow: 0 1px 2px rgba( 0, 0, 0, 0.45 );
578 transition: color 160ms ease-out;
579 }
580
581 .desktop-mode-dock-peek__card--ghost:hover .desktop-mode-dock-peek__card-plus {
582 color: var( --desktop-mode-accent, #4f9cff );
583 }
584
585 @keyframes desktop-mode-dock-peek-breathe {
586 0%, 100% {
587 opacity: 0.74;
588 transform: scale( 1 );
589 }
590 50% {
591 opacity: 1;
592 transform: scale( 1.018 );
593 }
594 }
595
596 @media ( prefers-reduced-motion: reduce ) {
597 .desktop-mode-dock-peek,
598 .desktop-mode-dock-peek__card,
599 .desktop-mode-dock-peek__card--ghost {
600 transition: opacity 80ms linear;
601 animation: none !important;
602 transform: none !important;
603 }
604 .desktop-mode-dock-peek--open .desktop-mode-dock-peek__card {
605 transform: none;
606 }
607 }
608
609 /* ──────────────────────────────────────────────────────────────────
610 View Transitions — when supported, an instance card morphs into
611 its window on click (and the Ghost Card morphs into the new
612 spawned window). The transition group is named per-card via
613 `--peek-card-vt-name`, set in JS at click time so the source +
614 destination share an identity.
615 ────────────────────────────────────────────────────────────────── */
616
617 @supports ( view-transition-name: none ) {
618 ::view-transition-old( root ),
619 ::view-transition-new( root ) {
620 animation-duration: 280ms;
621 animation-timing-function: cubic-bezier( 0.22, 1, 0.36, 1 );
622 }
623 }
624
625 /* Collapse minimized cards to just the titlebar. */
626 .desktop-mode-dock-peek__card[data-state="minimized"] {
627 min-height: 0;
628 opacity: 0.85;
629 }
630 .desktop-mode-dock-peek__card[data-state="minimized"] > :not(.desktop-mode-dock-peek__card-titlebar) {
631 display: none;
632 }
633