PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.12
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.12
1.1.12 1.1.11 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 All 36 releases
← All changes | assets/css/dock.css +220 -12 1.1.0 → 1.1.12 View file →
@@ -87,8 +87,19 @@
87 87 color: var( --os-dock-icon-color, rgba( 255, 255, 255, 0.7 ) );
88 88 transition: background-color 0.15s ease, transform 0.15s ease, color 0.15s ease;
89 89 }
90 90
91 +/*
92 + * The tile whose window is in front sits on a lit plate. Declared
93 + * before the hover rule at the same specificity so the pointer still
94 + * wins while it is over the tile. Falls back to nothing, which is
95 + * what every placement drew before the token existed.
96 + */
97 +.os-dock__item--focused .os-dock__item-primary {
98 + background-color: var( --os-dock-item-bg-focused, transparent );
99 + color: var( --os-dock-icon-color-hover, var( --os-ui-fg-on-accent, #fff ) );
100 +}
101 +
91 102 .os-dock__item-primary:hover {
92 103 background-color: var(
93 104 --os-dock-item-bg-hover,
94 105 rgba( 255, 255, 255, 0.15 )
@@ -113,21 +124,29 @@
113 124 }
114 125
115 126 /* Stacked card hint on hover — a second card peeks from behind the
116 127 icon when the tile has multiple open windows. Only visible on hover so
117 - it never conflicts with focused tiles. */
118 -.os-dock__item--stacked:hover .os-dock__item-primary::before,
119 -.os-dock__item--stacked[data-peek-active] .os-dock__item-primary::before {
128 + it never conflicts with focused tiles.
129 + *
130 + * Painted on the TILE, not on the button it hints at. The hover that
131 + * arms this also scales the button, a transform makes a stacking
132 + * context, and a `z-index: -1` child of one cannot escape it: the card
133 + * landed above the button's own hover plate instead of behind the
134 + * tile, reading as a second plate laid over the first. The tile is
135 + * transformed by nothing, and a positioned child (the button) paints
136 + * over a parent's `::before` at the same level, so the card sits where
137 + * its name says without asking for a z-index at all. */
138 +.os-dock__item--stacked:hover::before,
139 +.os-dock__item--stacked[ data-peek-active ]::before {
120 140 content: "";
121 141 position: absolute;
122 142 top: -4px;
123 143 inset-inline-start: -4px;
124 - width: 100%;
125 - height: 100%;
126 - border-radius: inherit;
144 + width: 40px;
145 + height: 40px;
146 + border-radius: 10px;
127 147 background: rgba( 255, 255, 255, 0.06 );
128 148 border: 1px solid rgba( 255, 255, 255, 0.10 );
129 - z-index: -1;
130 149 pointer-events: none;
131 150 }
132 151
133 152 /* Dashicon inside dock item. */
@@ -249,9 +268,9 @@
249 268 padding: 0;
250 269 border: 2px solid var( --os-dock-bg, rgba( 0, 0, 0, 0.4 ) );
251 270 border-radius: 50%;
252 271 background: var( --wp-admin-theme-color, #2271b1 );
253 - color: var( --os-ui-fg-on-accent, #fff );
272 + color: var( --os-ui-accent-ink, var( --os-ui-fg-on-accent, #fff ) );
254 273 cursor: pointer;
255 274 transition: background-color 0.15s ease, transform 0.15s ease;
256 275 z-index: 1;
257 276 }
@@ -1003,17 +1022,26 @@
1003 1022 * general problem. The inline padding is symmetric so the tile cluster
1004 1023 * stays centred in the pill. `min-width: 0` lets the wrapper shrink below its
1005 1024 * content's natural width, so the dock pill's `max-width` is what
1006 1025 * decides when scroll kicks in instead of the content forcing the
1007 - * pill wider. `justify-content: center` keeps tiles balanced inside
1008 - * the pill when content fits; when it overflows, scroll engages and
1009 - * items extend past the visible area.
1026 + * pill wider. `justify-content: safe center` keeps tiles balanced inside
1027 + * the pill when content fits; when it overflows, the `safe` keyword
1028 + * ensures alignment falls back to `start` so `scrollLeft = 0` reveals the
1029 + * first item and all items remain scrollable without clipping. Bare
1030 + * `center` put the leading tiles at a negative offset, and a scroll
1031 + * container clamps `scrollLeft` at 0, so Dashboard and its neighbours
1032 + * were clipped with no way to scroll back to them. **The plain `start`
1033 + * above it is the fallback, not a leftover** — a browser that cannot
1034 + * parse the overflow-alignment keyword drops the `safe center`
1035 + * declaration and keeps that one, which left-aligns the tiles rather
1036 + * than hiding them. Deleting it restores the bug on those browsers.
1010 1037 */
1011 1038 .os-dock[ data-os-dock-placement="bottom" ] .os-dock__scroll {
1012 1039 display: flex;
1013 1040 flex-direction: row;
1014 1041 align-items: center;
1015 - justify-content: center;
1042 + justify-content: start;
1043 + justify-content: safe center;
1016 1044 gap: 6px;
1017 1045 flex: 1 1 auto;
1018 1046 min-width: 0;
1019 1047 padding-top: 4px;
@@ -1243,6 +1271,186 @@
1243 1271 .os-dock[ data-os-dock-placement="right" ]
1244 1272 .os-dock__item[ data-system-id="os-exit" ]
1245 1273 .os-dock__item-primary:hover {
1246 1274 transform: none;
1275 + }
1276 +}
1277 +
1278 +/* ------------------------------------------------------------------
1279 + * Dynamic dock behavior — OpenStation Preferences → Appearance →
1280 + * Desktop layout, persisted as `dockBehavior` (the dock) and
1281 + * `sideDockBehavior` (the Split sidebar) and worn by each rail as
1282 + * `data-os-dock-behavior` — an attribute PER RAIL rather than a body
1283 + * class, because Split's two rails answer independently. PHP stamps
1284 + * the dock on first paint; the apply pass and `src/dock-behavior.ts`
1285 + * re-stamp on every change and rebuild. `static` is the absence of
1286 + * rules.
1287 + *
1288 + * A dynamic rail that is not `os-dock--revealed` is PARKED: it
1289 + * collapses into a thin indicator line hugging its edge — the iOS
1290 + * home indicator, one line that says "there is a dock here" — and
1291 + * expands back into the full rail when the pointer comes for it.
1292 + * `src/dock-behavior.ts` owns the flip (a full-width edge zone, the
1293 + * rail's own box, its flyouts, keyboard focus) and runs it through
1294 + * the View Transitions API, so the line morphs into the pill and
1295 + * back; the rules below only describe the two resting states and
1296 + * tune the morph. There is deliberately no `:hover` here — a state
1297 + * CSS flipped on its own would jump instead of morphing.
1298 + *
1299 + * The line is the rail itself, not a separate element: same node,
1300 + * same `view-transition-name`, which is what lets the browser animate
1301 + * one box into the other. Its children are hidden while parked so
1302 + * the line is a line. A side rail leaves the flex row for the
1303 + * duration, so the area grows to the full width and the rail rides
1304 + * over it when summoned; the work area reserves nothing for a
1305 + * dynamic rail (`src/work-area/index.ts`).
1306 + * ------------------------------------------------------------------ */
1307 +
1308 +/*
1309 + * Side rails overlay the area in both states — the flex row must not
1310 + * shrink for a rail that is only sometimes there.
1311 + */
1312 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="left" ],
1313 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="right" ] {
1314 + position: absolute;
1315 + inset-block: 0;
1316 +}
1317 +
1318 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="left" ] {
1319 + inset-inline-start: 0;
1320 +}
1321 +
1322 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="right" ] {
1323 + inset-inline-end: 0;
1324 +}
1325 +
1326 +/*
1327 + * Parked — the indicator line. Everything that makes the pill a
1328 + * pill (padding, border, blur, texture, tile gap) comes off, and the
1329 + * box is the line's size. `overflow: hidden` clips whatever a tile
1330 + * paints past its box during the morph.
1331 + */
1332 +.os-dock[ data-os-dock-behavior="dynamic" ]:not( .os-dock--revealed ) {
1333 + min-width: 0;
1334 + min-height: 0;
1335 + max-width: none;
1336 + padding: 0;
1337 + gap: 0;
1338 + border: 0;
1339 + border-radius: 999px;
1340 + overflow: hidden;
1341 + background-color: var(
1342 + --os-dock-indicator-bg,
1343 + var( --os-dock-item-outline, rgba( 255, 255, 255, 0.55 ) )
1344 + );
1345 + background-image: none;
1346 + backdrop-filter: none;
1347 + -webkit-backdrop-filter: none;
1348 + box-shadow: none;
1349 + cursor: pointer;
1350 +}
1351 +
1352 +.os-dock[ data-os-dock-behavior="dynamic" ]:not( .os-dock--revealed ) > * {
1353 + display: none;
1354 +}
1355 +
1356 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="bottom" ]:not( .os-dock--revealed ) {
1357 + width: var( --os-dock-indicator-length, 180px );
1358 + height: var( --os-dock-indicator-thickness, 5px );
1359 + bottom: 8px;
1360 +}
1361 +
1362 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="left" ]:not( .os-dock--revealed ),
1363 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="right" ]:not( .os-dock--revealed ) {
1364 + width: var( --os-dock-indicator-thickness, 5px );
1365 + height: var( --os-dock-indicator-length, 180px );
1366 + inset-block: calc( 50% - var( --os-dock-indicator-length, 180px ) / 2 );
1367 +}
1368 +
1369 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="left" ]:not( .os-dock--revealed ) {
1370 + inset-inline-start: 8px;
1371 +}
1372 +
1373 +.os-dock[ data-os-dock-behavior="dynamic" ][ data-os-dock-placement="right" ]:not( .os-dock--revealed ) {
1374 + inset-inline-end: 8px;
1375 +}
1376 +
1377 +/*
1378 + * The morph. With the API, `src/dock-behavior.ts` names the rail for
1379 + * the duration of one flip and the browser animates the old box into
1380 + * the new one; the rail's contents cross-fade underneath. The root is
1381 + * opted out of the snapshot so the rest of the desktop keeps
1382 + * running while the line becomes a pill — a frozen page for 260ms
1383 + * on every reveal would be the animation costing more than it
1384 + * gives. Without the API, the properties that can transition do.
1385 + */
1386 +@supports ( view-transition-name: none ) {
1387 + html.os-dock-vt {
1388 + view-transition-name: none;
1389 + }
1390 +
1391 + html.os-dock-vt::view-transition-old( root ),
1392 + html.os-dock-vt::view-transition-new( root ) {
1393 + animation: none;
1394 + }
1395 +
1396 + /*
1397 + * The transition layer must not catch the pointer. By default it
1398 + * does — the whole page reads as inert until the morph settles —
1399 + * and with the root opted out of the snapshot that is worse than
1400 + * pointless: the live desktop is right there under a layer that
1401 + * swallows every mouseup and every pointerenter for 260ms. The
1402 + * behavior module already holds a park back while a button is
1403 + * down; this is the other half, so a hover that lands on a tile
1404 + * while the rail is still morphing out starts its hover-intent
1405 + * timer instead of waiting for the next pointer movement.
1406 + */
1407 + html.os-dock-vt::view-transition {
1408 + pointer-events: none;
1409 + }
1410 +
1411 + ::view-transition-group( os-dock-os-dock ),
1412 + ::view-transition-group( os-dock-os-side-dock ) {
1413 + animation-duration: 260ms;
1414 + animation-timing-function: cubic-bezier( 0.22, 1, 0.36, 1 );
1415 + }
1416 +
1417 + ::view-transition-old( os-dock-os-dock ),
1418 + ::view-transition-old( os-dock-os-side-dock ) {
1419 + animation: os-dock-vt-out 120ms ease-out both;
1420 + }
1421 +
1422 + ::view-transition-new( os-dock-os-dock ),
1423 + ::view-transition-new( os-dock-os-side-dock ) {
1424 + animation: os-dock-vt-in 180ms ease-out 80ms both;
1425 + }
1426 +
1427 + @keyframes os-dock-vt-out {
1428 + to {
1429 + opacity: 0;
1430 + }
1431 + }
1432 +
1433 + @keyframes os-dock-vt-in {
1434 + from {
1435 + opacity: 0;
1436 + }
1437 + }
1438 +}
1439 +
1440 +@supports not ( view-transition-name: none ) {
1441 + .os-dock[ data-os-dock-behavior="dynamic" ] {
1442 + transition:
1443 + width 240ms ease,
1444 + height 240ms ease,
1445 + opacity 240ms ease,
1446 + border-radius 240ms ease,
1447 + bottom 240ms ease,
1448 + inset-block 240ms ease;
1449 + }
1450 +}
1451 +
1452 +@media ( prefers-reduced-motion: reduce ) {
1453 + .os-dock[ data-os-dock-behavior="dynamic" ] {
1454 + transition: none;
1247 1455 }
1248 1456 }