role-select UX: tray timing delays, seat/circle state polish, 394 ITs green
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- _animationPending set before fetch (not in .then()) — blocks WS turn advance during in-flight request
- _placeCardDelay (3s) + _postTrayDelay (3s) give gamer time to see each step; both zeroed by _testReset()
- .role-confirmed class: full-opacity chair after placeCard completes; server-rendered on reload
- Slot circles disappear in join order (slot 1 first) via count-based logic, not role-label matching
- data-active-slot on card-stack; handleTurnChanged writes it for selectRole() to read
- #id_tray_wrap not rendered during gate phase ({% if room.table_status %})
- Tray slide/arc-in slowed to 1s for diagnostics; wobble kept at 0.45s
- Obsolete test_roles_revealed_simultaneously FT removed; T8 tray FT uses ROLE_SELECT room
- Jasmine macrotask flush pattern: await new Promise(r => setTimeout(r, 0)) after fetch .then()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -239,68 +239,6 @@ html:has(.gate-backdrop) {
|
||||
}
|
||||
}
|
||||
|
||||
.gate-slots {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: $gate-gap;
|
||||
|
||||
.gate-slot {
|
||||
position: relative;
|
||||
width: $gate-node;
|
||||
height: $gate-node;
|
||||
border-radius: 50%;
|
||||
border: $gate-line solid rgba(var(--terUser), 1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.filled,
|
||||
&.reserved {
|
||||
background: rgba(var(--terUser), 0.2);
|
||||
}
|
||||
|
||||
&.filled:hover,
|
||||
&.reserved:hover {
|
||||
box-shadow:
|
||||
-0.1rem -0.1rem 1rem rgba(var(--ninUser), 1),
|
||||
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 1),
|
||||
0.05rem 0.05rem 0.5rem rgba(0, 0, 0, 1),
|
||||
;
|
||||
}
|
||||
|
||||
.slot-number {
|
||||
font-size: 0.7em;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.slot-gamer { display: none; }
|
||||
|
||||
form {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// CARTE drop-target circle — matches .reserved appearance
|
||||
&:has(.drop-token-btn) {
|
||||
background: rgba(var(--terUser), 0.2);
|
||||
|
||||
&:hover {
|
||||
box-shadow:
|
||||
-0.1rem -0.1rem 1rem rgba(var(--ninUser), 1),
|
||||
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 1),
|
||||
0.05rem 0.05rem 0.5rem rgba(0, 0, 0, 1),
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-container {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
@@ -317,24 +255,6 @@ html:has(.gate-backdrop) {
|
||||
}
|
||||
|
||||
.token-slot { min-width: 150px; }
|
||||
|
||||
.gate-slots {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 52px);
|
||||
grid-template-rows: repeat(2, 52px);
|
||||
gap: 24px;
|
||||
|
||||
.gate-slot {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
&:nth-child(1) { grid-column: 1; grid-row: 1; }
|
||||
&:nth-child(2) { grid-column: 2; grid-row: 1; }
|
||||
&:nth-child(3) { grid-column: 3; grid-row: 1; }
|
||||
&:nth-child(4) { grid-column: 1; grid-row: 2; }
|
||||
&:nth-child(5) { grid-column: 2; grid-row: 2; }
|
||||
&:nth-child(6) { grid-column: 3; grid-row: 2; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,59 +286,104 @@ $seat-r: 130px;
|
||||
$seat-r-x: round($seat-r * 0.866); // 113px
|
||||
$seat-r-y: round($seat-r * 0.5); // 65px
|
||||
|
||||
// .table-position anchors at edge midpoints (pointy-top hex).
|
||||
// Seat edge-midpoint geometry (pointy-top hex).
|
||||
// Apothem ≈ 80px + 30px clearance = 110px total push from centre.
|
||||
$pos-d: 110px;
|
||||
$pos-d-x: round($pos-d * 0.5); // 55px
|
||||
$pos-d-y: round($pos-d * 0.866); // 95px
|
||||
|
||||
.table-position {
|
||||
// ─── Position strip ────────────────────────────────────────────────────────
|
||||
// Numbered gate-slot circles rendered above the backdrop (z 130 > overlay 120
|
||||
// > backdrop 100). .room-page is position:relative with no z-index, so its
|
||||
// absolute children share the root stacking context with the fixed overlays.
|
||||
.position-strip {
|
||||
position: absolute;
|
||||
z-index: 110;
|
||||
pointer-events: none;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 0.5rem;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 130;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.15rem;
|
||||
justify-content: center;
|
||||
gap: round($gate-gap * 0.6);
|
||||
pointer-events: none;
|
||||
|
||||
// Edge midpoints, clockwise from 3 o'clock (slot drop order → role order)
|
||||
&[data-slot="1"] { left: calc(50% + #{$pos-d}); top: 50%; }
|
||||
&[data-slot="2"] { left: calc(50% + #{$pos-d-x}); top: calc(50% + #{$pos-d-y}); }
|
||||
&[data-slot="3"] { left: calc(50% - #{$pos-d-x}); top: calc(50% + #{$pos-d-y}); }
|
||||
&[data-slot="4"] { left: calc(50% - #{$pos-d}); top: 50%; }
|
||||
&[data-slot="5"] { left: calc(50% - #{$pos-d-x}); top: calc(50% - #{$pos-d-y}); }
|
||||
&[data-slot="6"] { left: calc(50% + #{$pos-d-x}); top: calc(50% - #{$pos-d-y}); }
|
||||
|
||||
.position-body {
|
||||
.gate-slot {
|
||||
position: relative;
|
||||
width: round($gate-node * 0.75);
|
||||
height: round($gate-node * 0.75);
|
||||
border-radius: 50%;
|
||||
border: $gate-line solid rgba(var(--terUser), 0.5);
|
||||
background: rgba(var(--priUser), 1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
}
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
pointer-events: auto;
|
||||
font-size: 1.8rem;
|
||||
transition: opacity 0.6s ease, transform 0.6s ease;
|
||||
box-shadow:
|
||||
0.1rem 0.1rem 0.12rem rgba(var(--priUser), 0.25),
|
||||
0.12rem 0.12rem 0.25rem rgba(0, 0, 0, 0.25),
|
||||
0.25rem 0.25rem 0.25rem rgba(var(--priUser), 0.12)
|
||||
;
|
||||
|
||||
.fa-chair {
|
||||
font-size: 1.1rem;
|
||||
color: rgba(var(--secUser), 0.4);
|
||||
}
|
||||
&.role-assigned {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
pointer-events: none;
|
||||
box-shadow:
|
||||
0.1rem 0.1rem 0.12rem rgba(var(--terUser), 0.25),
|
||||
0.12rem 0.12rem 0.25rem rgba(0, 0, 0, 0.25),
|
||||
0.25rem 0.25rem 0.25rem rgba(var(--terUser), 0.12)
|
||||
;
|
||||
}
|
||||
|
||||
.position-role-label {
|
||||
font-size: 0.6rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.05em;
|
||||
color: rgba(var(--secUser), 0.5);
|
||||
}
|
||||
&.filled, &.reserved {
|
||||
background: rgba(var(--terUser), 0.9);
|
||||
border-color: rgba(var(--terUser), 1);
|
||||
color: rgba(var(--priUser), 1);
|
||||
}
|
||||
|
||||
.position-status-icon {
|
||||
font-size: 0.65rem;
|
||||
&.fa-ban { color: rgba(var(--priRd), 1); }
|
||||
&.fa-circle-check { color: rgba(var(--priGn), 1); }
|
||||
}
|
||||
&.filled:hover, &.reserved:hover {
|
||||
box-shadow:
|
||||
-0.1rem -0.1rem 1rem rgba(var(--ninUser), 1),
|
||||
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 1),
|
||||
0.05rem 0.05rem 0.5rem rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
.fa-chair {
|
||||
color: rgba(var(--terUser), 1);
|
||||
filter: drop-shadow(0 0 4px rgba(var(--ninUser), 1));
|
||||
.slot-number { font-size: 0.7em; opacity: 0.5; }
|
||||
.slot-gamer { display: none; }
|
||||
|
||||
form {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&:has(.drop-token-btn) {
|
||||
background: rgba(var(--terUser), 1);
|
||||
border-color: rgba(var(--ninUser), 0.5);
|
||||
|
||||
&:hover {
|
||||
box-shadow:
|
||||
-0.1rem -0.1rem 1rem rgba(var(--ninUser), 1),
|
||||
-0.1rem -0.1rem 0.25rem rgba(0, 0, 0, 1),
|
||||
0.05rem 0.05rem 0.5rem rgba(0, 0, 0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.position-strip {
|
||||
gap: round($gate-gap * 0.3);
|
||||
|
||||
.gate-slot {
|
||||
width: round($gate-node * 0.75);
|
||||
height: round($gate-node * 0.75);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,20 +447,61 @@ $pos-d-y: round($pos-d * 0.866); // 95px
|
||||
|
||||
.table-seat {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
grid-template-rows: auto auto;
|
||||
column-gap: 0.25rem;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
// Centre the element on its anchor point
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
|
||||
// Clockwise from top — slot drop order during ROLE_SELECT
|
||||
&[data-slot="1"] { left: 50%; top: calc(50% - #{$seat-r}); }
|
||||
&[data-slot="2"] { left: calc(50% + #{$seat-r-x}); top: calc(50% - #{$seat-r-y}); }
|
||||
&[data-slot="3"] { left: calc(50% + #{$seat-r-x}); top: calc(50% + #{$seat-r-y}); }
|
||||
&[data-slot="4"] { left: 50%; top: calc(50% + #{$seat-r}); }
|
||||
&[data-slot="5"] { left: calc(50% - #{$seat-r-x}); top: calc(50% + #{$seat-r-y}); }
|
||||
&[data-slot="6"] { left: calc(50% - #{$seat-r-x}); top: calc(50% - #{$seat-r-y}); }
|
||||
// Edge midpoints, clockwise from 3 o'clock (slot drop order → role order)
|
||||
&[data-slot="1"] { left: calc(50% + #{$pos-d}); top: 50%; }
|
||||
&[data-slot="2"] { left: calc(50% + #{$pos-d-x}); top: calc(50% + #{$pos-d-y}); }
|
||||
&[data-slot="3"] { left: calc(50% - #{$pos-d-x}); top: calc(50% + #{$pos-d-y}); }
|
||||
&[data-slot="4"] { left: calc(50% - #{$pos-d}); top: 50%; }
|
||||
&[data-slot="5"] { left: calc(50% - #{$pos-d-x}); top: calc(50% - #{$pos-d-y}); }
|
||||
&[data-slot="6"] { left: calc(50% + #{$pos-d-x}); top: calc(50% - #{$pos-d-y}); }
|
||||
|
||||
// Chair: col 1, spans both rows
|
||||
.fa-chair {
|
||||
grid-column: 1;
|
||||
grid-row: 1 / 3;
|
||||
font-size: 1.6rem;
|
||||
color: rgba(var(--secUser), 0.4);
|
||||
transition: color 0.6s ease, filter 0.6s ease;
|
||||
}
|
||||
|
||||
// Abbreviation: col 2, row 1
|
||||
.seat-role-label {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.05em;
|
||||
color: rgba(var(--secUser), 1);
|
||||
}
|
||||
|
||||
// Status icon: col 2, row 2, centred under the abbreviation
|
||||
.position-status-icon {
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
justify-self: center;
|
||||
font-size: 0.8rem;
|
||||
&.fa-ban { color: rgba(var(--priRd), 1); }
|
||||
&.fa-circle-check { color: rgba(var(--priGn), 1); }
|
||||
}
|
||||
|
||||
&.active .fa-chair {
|
||||
color: rgba(var(--terUser), 1);
|
||||
filter: drop-shadow(0 0 4px rgba(var(--ninUser), 1));
|
||||
}
|
||||
|
||||
// After role confirmed: chair settles to full-opacity --secUser (no glow)
|
||||
&.role-confirmed .fa-chair {
|
||||
color: rgba(var(--secUser), 1);
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.seat-portrait {
|
||||
width: 36px;
|
||||
@@ -690,17 +696,6 @@ $card-h: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.gate-slots {
|
||||
gap: 14px;
|
||||
|
||||
.gate-slot {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
.slot-number { font-size: 0.6em; }
|
||||
}
|
||||
}
|
||||
|
||||
.form-container {
|
||||
margin-top: 0.75rem;
|
||||
h3 { font-size: 0.85rem; margin: 0.5rem 0; }
|
||||
|
||||
@@ -24,6 +24,10 @@ $handle-rect-h: 72px;
|
||||
$handle-exposed: 48px;
|
||||
$handle-r: 1rem;
|
||||
|
||||
#id_tray_wrap.role-select-phase {
|
||||
#id_tray_handle { visibility: hidden; pointer-events: none; }
|
||||
}
|
||||
|
||||
#id_tray_wrap {
|
||||
position: fixed;
|
||||
// left set by JS: closed = vw - handleW; open = vw - wrapW
|
||||
@@ -37,11 +41,11 @@ $handle-r: 1rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
transition: left 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: left 1.0s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&.tray-dragging { transition: none; }
|
||||
&.wobble { animation: tray-wobble 0.45s ease; }
|
||||
&.snap { animation: tray-snap 0.30s ease; }
|
||||
&.wobble { animation: tray-wobble .45s ease; }
|
||||
&.snap { animation: tray-snap 1.0s ease; }
|
||||
}
|
||||
|
||||
#id_tray_handle {
|
||||
@@ -134,7 +138,7 @@ $handle-r: 1rem;
|
||||
font-weight: 600;
|
||||
|
||||
&.arc-in {
|
||||
animation: tray-role-arc-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
animation: tray-role-arc-in 1.0s cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,11 +222,11 @@ $handle-r: 1rem;
|
||||
right: $sidebar-w;
|
||||
top: auto; // JS controls style.top for the Y-axis slide
|
||||
bottom: auto;
|
||||
transition: top 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: top 1.0s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&.tray-dragging { transition: none; }
|
||||
&.wobble { animation: tray-wobble-landscape 0.45s ease; }
|
||||
&.snap { animation: tray-snap-landscape 0.30s ease; }
|
||||
&.snap { animation: tray-snap-landscape 1.0s ease; }
|
||||
|
||||
}
|
||||
|
||||
@@ -304,7 +308,7 @@ $handle-r: 1rem;
|
||||
}
|
||||
|
||||
.tray-role-card.arc-in {
|
||||
animation: tray-role-arc-in-landscape 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
animation: tray-role-arc-in-landscape 1.0s cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
}
|
||||
|
||||
@keyframes tray-wobble-landscape {
|
||||
|
||||
Reference in New Issue
Block a user