This commit is contained in:
@@ -23,9 +23,17 @@
|
||||
// WARNING: do NOT add max-width or overflow here; the outer window also carries this class
|
||||
// and would clip the expanded inner content.
|
||||
.scrying-pool-strip {
|
||||
background: var(--sp-bg, hsl(220, 15%, 12%));
|
||||
background: rgba(0, 0, 0, 0.01);
|
||||
border-radius: 8px;
|
||||
|
||||
transition: background 0.25s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Override FoundryVTT v14's .application min-width: 200px — strip sizing is controlled by JS */
|
||||
min-width: unset;
|
||||
|
||||
/* Ensure strip appears below Director's Board (z-index: 100) */
|
||||
z-index: 50;
|
||||
|
||||
@@ -46,14 +54,10 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 83px;
|
||||
max-width: calc(var(--sp-widget-width, 83px) + 11px);
|
||||
overflow: hidden;
|
||||
transition: max-width 200ms ease-in-out;
|
||||
|
||||
&.is-expanded {
|
||||
max-width: 240px;
|
||||
}
|
||||
|
||||
// Horizontal and mosaic layouts: width is controlled by JS setPosition
|
||||
&.sp-layout-horizontal-sm,
|
||||
&.sp-layout-horizontal-md,
|
||||
@@ -100,18 +104,16 @@
|
||||
.scrying-pool.scrying-pool-strip.sp-layout-horizontal-md,
|
||||
.scrying-pool.scrying-pool-strip.sp-layout-mosaic-md {
|
||||
.sp-participant-avatar {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
width: var(--sp-widget-width, 150px);
|
||||
height: var(--sp-widget-width, 150px);
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 8px 4px 4px;
|
||||
gap: 4px;
|
||||
|
||||
.sp-avatar__img {
|
||||
width: 91px;
|
||||
height: 91px;
|
||||
border-radius: 6px;
|
||||
flex-shrink: 0;
|
||||
.sp-avatar__shell {
|
||||
width: calc(var(--sp-widget-width, 150px) - 59px);
|
||||
height: calc(var(--sp-widget-width, 150px) - 59px);
|
||||
}
|
||||
|
||||
.sp-avatar__name {
|
||||
@@ -134,66 +136,52 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ── Drag grip (top bar, replaces window header drag affordance) ────────────────
|
||||
.sp-strip__grip {
|
||||
width: 100%;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: grab;
|
||||
color: var(--sp-text, hsl(0, 0%, 80%));
|
||||
opacity: 0.35;
|
||||
font-size: 10px;
|
||||
flex-shrink: 0;
|
||||
transition: opacity 0.15s;
|
||||
user-select: none;
|
||||
|
||||
&:hover { opacity: 0.75; }
|
||||
&:active { cursor: grabbing; opacity: 1; }
|
||||
}
|
||||
|
||||
// ── Lightweight close button (replaces window header) ─────────────────────────
|
||||
.sp-strip__close-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
z-index: 10;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
line-height: 18px;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
background: transparent;
|
||||
color: var(--sp-text, hsl(0, 0%, 80%));
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
opacity: 0.45;
|
||||
transition: opacity 0.15s, background 0.15s;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
&:active { opacity: 0.75; }
|
||||
}
|
||||
|
||||
// ── Toolbar row: toggle + Director's Board on the same line ───────────────────
|
||||
// ── Toolbar: grip + toggle + DB + close on one line ─────────────────────────
|
||||
// All chrome lives here; hidden at rest, revealed on strip hover.
|
||||
.sp-strip__toolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
.scrying-pool-strip:hover & {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// Drag grip — compact icon handle
|
||||
.sp-strip__grip {
|
||||
width: 20px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: grab;
|
||||
color: var(--sp-text, hsl(0, 0%, 80%));
|
||||
font-size: 10px;
|
||||
flex-shrink: 0;
|
||||
user-select: none;
|
||||
|
||||
&:active { cursor: grabbing; }
|
||||
|
||||
.scrying-pool-strip:hover & {
|
||||
opacity: 0.45;
|
||||
&:hover { opacity: 0.75; }
|
||||
&:active { opacity: 1; }
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle (expand/collapse)
|
||||
.sp-strip__toggle {
|
||||
width: 83px;
|
||||
min-width: 83px;
|
||||
height: 28px;
|
||||
height: 24px;
|
||||
min-width: 22px;
|
||||
width: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -201,34 +189,27 @@
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--sp-text, hsl(0, 0%, 80%));
|
||||
font-size: 11px;
|
||||
font-size: 10px;
|
||||
flex-shrink: 0;
|
||||
opacity: 0.6;
|
||||
|
||||
&:hover { opacity: 1; }
|
||||
}
|
||||
|
||||
// ── Director's Board CTA button (shown when sidebar injection not available) ──
|
||||
// Director's Board CTA button
|
||||
.sp-strip__directors-board-cta {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 28px;
|
||||
width: 22px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 0 8px;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
border-left: 1px solid rgba(255, 255, 255, 0.06);
|
||||
cursor: pointer;
|
||||
color: var(--sp-text-secondary, #7a8390);
|
||||
font-size: 11px;
|
||||
text-align: left;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
flex-shrink: 0;
|
||||
|
||||
i { font-size: 12px; flex-shrink: 0; }
|
||||
span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
@@ -236,6 +217,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer — pushes close button to the right
|
||||
.sp-strip__toolbar-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
// Close button — in-toolbar, no longer absolutely positioned
|
||||
.sp-strip__close-btn {
|
||||
width: 20px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
background: transparent;
|
||||
color: var(--sp-text, hsl(0, 0%, 80%));
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
opacity: 0.45;
|
||||
transition: opacity 0.2s, background 0.15s;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
&:active { opacity: 0.75; }
|
||||
}
|
||||
|
||||
.sp-strip__participants {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
@@ -255,6 +265,12 @@
|
||||
color: var(--sp-text-muted, hsl(0, 0%, 60%));
|
||||
padding: 4px 8px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
.scrying-pool-strip:hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -263,7 +279,7 @@
|
||||
.sp-participant-avatar {
|
||||
position: relative;
|
||||
width: 83px;
|
||||
height: 83px;
|
||||
height: var(--sp-widget-width, 83px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
@@ -281,52 +297,30 @@
|
||||
}
|
||||
|
||||
.is-expanded & {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 135px; // 16:9 at 240 px strip width
|
||||
padding: 0;
|
||||
align-items: flex-end;
|
||||
background: hsl(220, 15%, 14%);
|
||||
height: auto;
|
||||
padding: 5px;
|
||||
background: transparent;
|
||||
|
||||
// Gradient scrim so name text is legible over any video
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 48px;
|
||||
background: linear-gradient(transparent, hsla(0, 0%, 0%, 0.72));
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
border-radius: 0 0 4px 4px;
|
||||
&:hover {
|
||||
background: hsl(220, 15%, 14%);
|
||||
}
|
||||
|
||||
.sp-avatar__img {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 6px; // card view — rectangular
|
||||
}
|
||||
|
||||
.sp-avatar__name {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
z-index: 3;
|
||||
color: hsl(0, 0%, 95%);
|
||||
&::after { display: none; }
|
||||
|
||||
// Shell: sized to widget width, centered in the card
|
||||
.sp-avatar__shell {
|
||||
width: calc(var(--sp-widget-width) - 59px);
|
||||
height: calc(var(--sp-widget-width) - 59px);
|
||||
}
|
||||
|
||||
// No names displayed in vertical mode
|
||||
.sp-avatar__name,
|
||||
.sp-avatar__state-label {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
left: 8px;
|
||||
z-index: 3;
|
||||
color: hsla(0, 0%, 85%, 0.85);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sp-avatar__corner-badge {
|
||||
@@ -339,23 +333,86 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Video container for WebRTC stream (full AV replacement mode)
|
||||
.sp-participant-video {
|
||||
// Border shell — no clip-path, no background. Serves only as the positioning
|
||||
// parent for ::before (border), ::after (state ring), and .sp-avatar__shape (content).
|
||||
// Border and ring use the SAME clip-path as the shape but are scaled up via
|
||||
// negative inset, creating a genuine border/ring around the clipped shape.
|
||||
.sp-avatar__shell {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// Default sm size — overridden by layout-specific CSS
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
// Tile border — ::before with same clip-path as shape, scaled up by border-width.
|
||||
// Hidden via opacity when --sp-tile-border-active is 0 (border-width = 0)
|
||||
// so the border background doesn't bleed through transparent avatar areas.
|
||||
.sp-avatar__shell::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
inset: calc(var(--sp-tile-border-width, 0px) * -1);
|
||||
background: var(--sp-tile-border-color, transparent);
|
||||
clip-path: var(--sp-shape-clip, none);
|
||||
opacity: var(--sp-tile-border-active, 1);
|
||||
z-index: -3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// State ring — ::after with same clip-path, scaled up same as border.
|
||||
// Uses inset box-shadow so the ring appears INSIDE the clipped area,
|
||||
// overlaying either the border (via ::before behind) or the avatar content.
|
||||
// At z-index 1 it renders above .sp-avatar__shape so the ring is visible
|
||||
// on top of the avatar video/img.
|
||||
// Gated by --sp-tile-border-active alongside the border ::before so that
|
||||
// "None" border truly removes ALL colored rings.
|
||||
.sp-avatar__shell::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: calc(var(--sp-tile-border-width, 0px) * -1);
|
||||
background: transparent;
|
||||
box-shadow: inset 0 0 0 2px transparent;
|
||||
clip-path: var(--sp-shape-clip, none);
|
||||
opacity: var(--sp-tile-border-active, 1);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
transition: box-shadow 200ms ease, opacity 200ms ease;
|
||||
}
|
||||
|
||||
// Shape wrapper inside the shell — carries clip-path for shapes.
|
||||
.sp-avatar__shape {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
clip-path: var(--sp-shape-clip, none);
|
||||
}
|
||||
|
||||
// Inner content (img and video) fill the shape
|
||||
.sp-avatar__shape .sp-avatar__img,
|
||||
.sp-avatar__shape .sp-participant-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// Video container for WebRTC stream (full AV replacement mode)
|
||||
// Regular flow child inside .sp-avatar__shell — contributes to shell sizing
|
||||
.sp-participant-video {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sp-avatar__img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 6px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -365,7 +422,6 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
background: hsl(220, 15%, 18%);
|
||||
|
||||
.is-expanded & {
|
||||
@@ -398,40 +454,50 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--sp-text, hsl(0, 0%, 85%));
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
.sp-participant-avatar:hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.sp-avatar__state-label {
|
||||
font-size: 0.7rem;
|
||||
color: var(--sp-text-muted, hsl(0, 0%, 60%));
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
.sp-participant-avatar:hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// StateRing variants (applied as class on .sp-participant-avatar)
|
||||
// ============================================================
|
||||
// State ring via ::after on the shell — uses inset box-shadow so the ring
|
||||
// follows the same clip-path as the shape, overlaying the border's inner edge.
|
||||
// When there's no border (width=0), the ring overlays the avatar content edge.
|
||||
.sp-participant-avatar.sp-state-active,
|
||||
.sp-participant-avatar.sp-state-self-muted {
|
||||
--sp-state-color: var(--sp-state-active);
|
||||
|
||||
.sp-avatar__img {
|
||||
box-shadow: 0 0 0 2px var(--sp-state-color);
|
||||
.sp-avatar__shell::after {
|
||||
box-shadow: inset 0 0 0 2px var(--sp-state-color);
|
||||
}
|
||||
}
|
||||
|
||||
.sp-participant-avatar.sp-state-hidden,
|
||||
.sp-participant-avatar.sp-state-cam-lost {
|
||||
--sp-state-color: var(--sp-state-hidden);
|
||||
|
||||
.sp-avatar__img {
|
||||
outline: 2px dashed var(--sp-state-color);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.sp-participant-avatar.sp-state-pending {
|
||||
--sp-state-color: var(--sp-state-pending);
|
||||
|
||||
.sp-avatar__img {
|
||||
box-shadow: 0 0 0 2px var(--sp-state-color);
|
||||
.sp-avatar__shell::after {
|
||||
box-shadow: inset 0 0 0 2px var(--sp-state-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +505,7 @@
|
||||
// StateRing animations — gated under no-preference (AC-16)
|
||||
// ============================================================
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.sp-participant-avatar.sp-state-pending .sp-avatar__img {
|
||||
.sp-participant-avatar.sp-state-pending .sp-avatar__shell::after {
|
||||
animation: sp-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -449,13 +515,13 @@
|
||||
}
|
||||
|
||||
// Revert flash (200ms amber, then restore)
|
||||
.sp-participant-avatar.sp-state-revert .sp-avatar__img {
|
||||
.sp-participant-avatar.sp-state-revert .sp-avatar__shell::after {
|
||||
animation: sp-revert-flash 200ms ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes sp-revert-flash {
|
||||
0% { box-shadow: 0 0 0 3px var(--sp-urgency-director); }
|
||||
100% { box-shadow: 0 0 0 2px var(--sp-state-color); }
|
||||
0% { box-shadow: inset 0 0 0 3px var(--sp-urgency-director); }
|
||||
100% { box-shadow: inset 0 0 0 2px var(--sp-state-color); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,3 +657,30 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Tile shape variants (applied as .sp-shape-* on .sp-participant-avatar)
|
||||
// ============================================================
|
||||
// Defines --sp-shape-clip which is consumed by:
|
||||
// - .sp-avatar__shape (content clip)
|
||||
// - .sp-avatar__shell::before (border)
|
||||
// - .sp-avatar__shell::after (state ring)
|
||||
// All three use the same clip-path, but ::before and ::after are scaled up
|
||||
// via negative inset to create the border/ring around the clipped shape.
|
||||
.sp-participant-avatar {
|
||||
&.sp-shape-rounded {
|
||||
--sp-shape-clip: inset(0 round 6px);
|
||||
}
|
||||
|
||||
&.sp-shape-circle {
|
||||
--sp-shape-clip: circle(50%);
|
||||
}
|
||||
|
||||
&.sp-shape-hexagon {
|
||||
--sp-shape-clip: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
|
||||
}
|
||||
|
||||
&.sp-shape-octagon {
|
||||
--sp-shape-clip: polygon(29% 0%, 71% 0%, 100% 29%, 100% 71%, 71% 100%, 29% 100%, 0% 71%, 0% 29%);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user