feat: animated border on active FAB and grayscale inactive FABs
Active terminal FAB shows a rotating conic-gradient border animation (cyan/indigo) on all three locations: main FAB (T1), AgentBadge, and mini FABs (T2-T5). Inactive FABs appear in grayscale with reduced brightness, brightening slightly on hover.
This commit is contained in:
@@ -85,6 +85,13 @@ const keyboardVisible = ref(false) // Virtual keyboard visible
|
|||||||
// Whether any terminal exists (T1+)
|
// Whether any terminal exists (T1+)
|
||||||
const hasTerminals = computed(() => sessionState.terminalRegistry.length > 0)
|
const hasTerminals = computed(() => sessionState.terminalRegistry.length > 0)
|
||||||
|
|
||||||
|
// Whether terminal 1 is the currently active terminal
|
||||||
|
const isT1Active = computed(() => {
|
||||||
|
const reg = sessionState.terminalRegistry
|
||||||
|
if (!reg.length) return false
|
||||||
|
return reg[0].transcriptSessionId === transcriptDebugRef.value?.activeTerminalSessionId
|
||||||
|
})
|
||||||
|
|
||||||
// Extra terminals (T2-T5) from Pinia store — fully reactive, no template ref dependency
|
// Extra terminals (T2-T5) from Pinia store — fully reactive, no template ref dependency
|
||||||
const extraTerminals = computed(() => {
|
const extraTerminals = computed(() => {
|
||||||
const reg = sessionState.terminalRegistry
|
const reg = sessionState.terminalRegistry
|
||||||
@@ -366,7 +373,7 @@ watch(() => route.name, (newPage) => {
|
|||||||
<span class="fab-bubble b3"></span>
|
<span class="fab-bubble b3"></span>
|
||||||
<button
|
<button
|
||||||
class="transcript-fab"
|
class="transcript-fab"
|
||||||
:class="{ active: showTranscriptDebug }"
|
:class="{ active: showTranscriptDebug, 't1-active': isT1Active }"
|
||||||
@click="handleMainFabClick"
|
@click="handleMainFabClick"
|
||||||
@contextmenu.prevent
|
@contextmenu.prevent
|
||||||
title="Transcript Debug"
|
title="Transcript Debug"
|
||||||
@@ -845,8 +852,8 @@ watch(() => route.name, (newPage) => {
|
|||||||
box-shadow:
|
box-shadow:
|
||||||
0 2px 4px rgba(0, 0, 0, 0.5),
|
0 2px 4px rgba(0, 0, 0, 0.5),
|
||||||
0 6px 16px rgba(0, 0, 0, 0.6),
|
0 6px 16px rgba(0, 0, 0, 0.6),
|
||||||
0 12px 28px rgba(0, 0, 0, 0.4),
|
0 12px 28px rgba(0, 0, 0, 0.4);
|
||||||
inset 0 1px 0 rgba(14, 165, 233, 0.12);
|
filter: grayscale(1) brightness(0.6);
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -867,15 +874,14 @@ watch(() => route.name, (newPage) => {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transcript-fab:hover {
|
.transcript-fab:not(.t1-active):hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
border-color: rgba(14, 165, 233, 0.35);
|
border-color: rgba(14, 165, 233, 0.35);
|
||||||
|
filter: grayscale(0.5) brightness(0.8);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 4px 8px rgba(0, 0, 0, 0.5),
|
0 4px 8px rgba(0, 0, 0, 0.5),
|
||||||
0 10px 24px rgba(0, 0, 0, 0.6),
|
0 10px 24px rgba(0, 0, 0, 0.6),
|
||||||
0 16px 36px rgba(0, 0, 0, 0.4),
|
0 0 14px rgba(14, 165, 233, 0.15);
|
||||||
0 0 14px rgba(14, 165, 233, 0.15),
|
|
||||||
inset 0 1px 0 rgba(14, 165, 233, 0.2);
|
|
||||||
color: #38bdf8;
|
color: #38bdf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,6 +894,31 @@ watch(() => route.name, (newPage) => {
|
|||||||
color: #a5f3fc;
|
color: #a5f3fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.transcript-fab.t1-active {
|
||||||
|
border: 2px solid;
|
||||||
|
border-image: conic-gradient(
|
||||||
|
from var(--border-angle, 0deg),
|
||||||
|
rgba(34, 211, 238, 1),
|
||||||
|
rgba(99, 102, 241, 0.7),
|
||||||
|
rgba(34, 211, 238, 0.15),
|
||||||
|
rgba(99, 102, 241, 0.7),
|
||||||
|
rgba(34, 211, 238, 1)
|
||||||
|
) 1;
|
||||||
|
filter: none;
|
||||||
|
box-shadow: 0 0 12px rgba(34, 211, 238, 0.3);
|
||||||
|
animation: border-spin 3s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property --border-angle {
|
||||||
|
syntax: "<angle>";
|
||||||
|
initial-value: 0deg;
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes border-spin {
|
||||||
|
to { --border-angle: 360deg; }
|
||||||
|
}
|
||||||
|
|
||||||
.fab-button-area {
|
.fab-button-area {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 44px;
|
width: 44px;
|
||||||
|
|||||||
@@ -625,7 +625,7 @@ onBeforeUnmount(() => {
|
|||||||
<AgentBadge
|
<AgentBadge
|
||||||
v-if="selectedAgent"
|
v-if="selectedAgent"
|
||||||
:agent="selectedAgent"
|
:agent="selectedAgent"
|
||||||
:connected="isRealtime"
|
:connected="!!activeTerminalSessionId"
|
||||||
:terminals="openTerminals"
|
:terminals="openTerminals"
|
||||||
:active-session-id="activeTerminalSessionId"
|
:active-session-id="activeTerminalSessionId"
|
||||||
:model="conversation?.model"
|
:model="conversation?.model"
|
||||||
|
|||||||
@@ -147,14 +147,32 @@ onBeforeUnmount(() => document.removeEventListener('mousedown', onClickOutside))
|
|||||||
}
|
}
|
||||||
|
|
||||||
.agent-badge-wrapper.connected {
|
.agent-badge-wrapper.connected {
|
||||||
border-color: rgba(34, 197, 94, 0.35);
|
border: 2px solid;
|
||||||
|
border-image: conic-gradient(
|
||||||
|
from var(--border-angle, 0deg),
|
||||||
|
rgba(34, 211, 238, 1),
|
||||||
|
rgba(99, 102, 241, 0.7),
|
||||||
|
rgba(34, 211, 238, 0.15),
|
||||||
|
rgba(99, 102, 241, 0.7),
|
||||||
|
rgba(34, 211, 238, 1)
|
||||||
|
) 1;
|
||||||
background: rgba(34, 197, 94, 0.08);
|
background: rgba(34, 197, 94, 0.08);
|
||||||
box-shadow: 0 0 8px rgba(34, 197, 94, 0.15);
|
box-shadow: 0 0 12px rgba(34, 211, 238, 0.3);
|
||||||
|
animation: border-spin 3s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-badge-wrapper.connected:hover {
|
.agent-badge-wrapper.connected:hover {
|
||||||
background: rgba(34, 197, 94, 0.15);
|
background: rgba(34, 197, 94, 0.15);
|
||||||
border-color: rgba(34, 197, 94, 0.5);
|
}
|
||||||
|
|
||||||
|
@property --border-angle {
|
||||||
|
syntax: "<angle>";
|
||||||
|
initial-value: 0deg;
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes border-spin {
|
||||||
|
to { --border-angle: 360deg; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-label {
|
.agent-label {
|
||||||
|
|||||||
@@ -86,27 +86,51 @@ const artVariants = [
|
|||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
filter: grayscale(1) brightness(0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal-fab:hover {
|
.terminal-fab:not(.active):hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
border-color: rgba(14, 165, 233, 0.35);
|
border-color: rgba(14, 165, 233, 0.35);
|
||||||
|
filter: grayscale(0.5) brightness(0.8);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 4px 8px rgba(0, 0, 0, 0.5),
|
0 4px 8px rgba(0, 0, 0, 0.5),
|
||||||
0 10px 24px rgba(0, 0, 0, 0.6),
|
0 10px 24px rgba(0, 0, 0, 0.6),
|
||||||
0 0 14px rgba(14, 165, 233, 0.15),
|
0 0 14px rgba(14, 165, 233, 0.15);
|
||||||
inset 0 1px 0 rgba(14, 165, 233, 0.2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal-fab:active {
|
.terminal-fab:active {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.terminal-fab:focus,
|
||||||
|
.terminal-fab:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
.terminal-fab.active {
|
.terminal-fab.active {
|
||||||
border-color: rgba(34, 211, 238, 0.4);
|
border: 2px solid;
|
||||||
box-shadow:
|
border-image: conic-gradient(
|
||||||
0 0 6px rgba(34, 211, 238, 0.15),
|
from var(--border-angle, 0deg),
|
||||||
inset 0 0 4px rgba(34, 211, 238, 0.08);
|
rgba(34, 211, 238, 1),
|
||||||
|
rgba(99, 102, 241, 0.7),
|
||||||
|
rgba(34, 211, 238, 0.15),
|
||||||
|
rgba(99, 102, 241, 0.7),
|
||||||
|
rgba(34, 211, 238, 1)
|
||||||
|
) 1;
|
||||||
|
filter: none;
|
||||||
|
box-shadow: 0 0 12px rgba(34, 211, 238, 0.3);
|
||||||
|
animation: border-spin 3s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property --border-angle {
|
||||||
|
syntax: "<angle>";
|
||||||
|
initial-value: 0deg;
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes border-spin {
|
||||||
|
to { --border-angle: 360deg; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.fab-number {
|
.fab-number {
|
||||||
|
|||||||
Reference in New Issue
Block a user