Files
CodeNomad/packages/ui/src/styles/panels.css
Shantur 3f6cdd36f3 feat(ui): surface retrying session status
Preserve retry metadata from session.status events so the session list and header can show a live retry countdown with context. Notify users when a session enters retry and reuse the existing error styling so retrying feels actionable without losing the current badge layout.
2026-03-31 18:38:54 +01:00

528 lines
12 KiB
CSS

@import "./panels/tabs.css";
@import "./panels/empty-loading.css";
@import "./panels/modal.css";
@import "./panels/panel-shell.css";
@import "./panels/session-layout.css";
@import "./panels/right-panel.css";
.tab-bar-instance {
background-color: var(--surface-secondary);
}
.tab-bar-session {
background-color: var(--surface-base);
}
.tab-container {
@apply flex items-center justify-between gap-1 px-2 py-1 overflow-x-auto;
}
.tab-base {
@apply inline-flex items-center gap-2 px-3 py-2 rounded-t-md max-w-[200px] transition-colors text-sm font-medium;
font-family: var(--font-family-sans);
outline: none;
}
.tab-base:focus-visible {
@apply ring-2 ring-offset-1;
ring-color: var(--accent-primary);
ring-offset-color: var(--surface-base);
}
.tab-active {
background-color: var(--tab-active-bg);
color: var(--tab-active-text);
border-bottom: 2px solid var(--accent-primary);
}
.tab-inactive {
background-color: var(--tab-inactive-bg);
color: var(--tab-inactive-text);
border-bottom: 2px solid var(--tab-active-bg);
}
.tab-inactive:hover {
background-color: var(--tab-inactive-hover-bg);
}
.tab-active:hover {
background-color: var(--tab-active-hover-bg);
}
.tab-label {
@apply truncate;
}
.tab-close {
@apply opacity-100 hover:bg-red-500 hover:text-white rounded p-0.5 transition-all cursor-pointer;
}
.tab-close:focus-visible {
@apply ring-2 ring-offset-1;
ring-color: var(--accent-primary);
ring-offset-color: inherit;
}
.new-tab-button {
@apply inline-flex items-center justify-center w-8 h-8 rounded-md transition-colors;
background-color: var(--new-tab-bg);
color: var(--new-tab-text);
}
.new-tab-button:hover {
background-color: var(--new-tab-hover-bg);
}
.new-tab-button:focus-visible {
@apply ring-2 ring-offset-1;
ring-color: var(--accent-primary);
ring-offset-color: var(--surface-base);
}
/* Session tab specific styles */
.session-tab-base {
@apply inline-flex items-center gap-2 px-3 py-1.5 rounded-t-md max-w-[150px] transition-colors text-sm;
font-family: var(--font-family-sans);
outline: none;
border-bottom: 2px solid transparent;
}
.session-tab-base:focus-visible {
@apply ring-2 ring-offset-1;
ring-color: var(--accent-primary);
ring-offset-color: var(--surface-base);
}
.session-tab-active {
background-color: var(--session-tab-active-bg);
border-bottom-color: var(--accent-primary);
color: var(--session-tab-active-text);
font-weight: var(--font-weight-medium);
}
.session-tab-inactive {
color: var(--session-tab-inactive-text);
}
.session-tab-inactive:hover {
background-color: var(--session-tab-hover-bg);
}
.session-tab-special {
color: var(--session-tab-inactive-text);
}
.connection-status-info {
justify-self: start;
}
.connection-status-shortcut {
justify-self: center;
text-align: center;
}
.connection-status-meta {
justify-self: end;
}
.connection-status-text {
color: var(--text-muted);
}
.sidebar-selector-hint {
@apply flex justify-center text-xs w-full;
color: var(--text-muted);
}
.session-sidebar-selector-hints {
@apply flex flex-wrap items-center w-full text-xs;
justify-content: space-evenly;
gap: 4px;
color: var(--text-muted);
}
.session-header-hints {
@apply flex-shrink-0;
}
.session-sidebar-controls .selector-trigger,
.session-sidebar-controls [data-model-selector-control],
.session-sidebar-controls .selector-trigger-label,
.session-sidebar-controls .selector-trigger-primary {
@apply w-full;
}
.sidebar-selector {
@apply flex flex-col gap-1 w-full;
}
.status-indicator {
@apply flex items-center gap-1.5 text-xs;
color: var(--text-muted);
}
.status-indicator .status-dot {
@apply w-2 h-2 rounded-full;
}
.status-indicator.connected .status-dot {
background-color: var(--status-success);
}
.status-indicator.connecting .status-dot {
background-color: var(--status-warning);
animation: pulse 1.5s ease-in-out infinite;
}
.status-indicator.disconnected .status-dot {
background-color: var(--status-error);
}
.status-indicator.session-status {
--session-status-dot: var(--text-muted);
}
.status-indicator.session-status.session-working,
.status-indicator.session-status.session-retrying,
.status-indicator.session-status.session-compacting,
.status-indicator.session-status.session-idle {
font-weight: var(--font-weight-medium);
}
.status-indicator.session-status.session-working {
color: var(--session-status-working-fg);
--session-status-dot: var(--session-status-working-fg);
}
.status-indicator.session-status.session-retrying {
color: var(--status-error);
--session-status-dot: var(--status-error);
}
.status-indicator.session-status.session-compacting {
color: var(--session-status-compacting-fg);
--session-status-dot: var(--session-status-compacting-fg);
}
.status-indicator.session-status.session-idle {
color: var(--session-status-idle-fg);
--session-status-dot: var(--session-status-idle-fg);
}
.status-indicator.session-status.session-permission {
color: var(--session-status-permission-fg);
--session-status-dot: var(--session-status-permission-fg);
}
.status-indicator.session-status .status-dot {
background-color: var(--session-status-dot);
}
.status-indicator.session-status.session-working .status-dot,
.status-indicator.session-status.session-compacting .status-dot {
animation: pulse 1.5s ease-in-out infinite;
}
.status-indicator.session-status.session-working.session-status-list {
background-color: var(--session-status-working-bg);
}
.status-indicator.session-status.session-retrying.session-status-list {
background-color: var(--status-error-bg);
}
.status-indicator.session-status.session-compacting.session-status-list {
background-color: var(--session-status-compacting-bg);
}
.status-indicator.session-status.session-idle.session-status-list {
background-color: var(--session-status-idle-bg);
}
.status-indicator.session-status.session-permission.session-status-list {
background-color: var(--session-status-permission-bg);
}
.status-indicator.session-status-list {
font-size: 0.65rem;
text-transform: uppercase;
letter-spacing: 0.05em;
font-weight: var(--font-weight-medium);
color: inherit;
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
border: 1px solid transparent;
}
/* Session list worktree pill */
.status-indicator.worktree-indicator {
/* Match session title in selected state. */
color: var(--text-primary);
/* Use inactive session title color as the tint source. */
background-color: color-mix(in oklab, var(--text-secondary) 18%, transparent);
border-color: color-mix(in oklab, var(--text-secondary) 28%, transparent);
text-transform: none;
letter-spacing: 0.02em;
}
.session-item-active .status-indicator.worktree-indicator {
background-color: color-mix(in oklab, var(--text-primary) 14%, transparent);
border-color: color-mix(in oklab, var(--text-primary) 22%, transparent);
}
.status-indicator.worktree-indicator .worktree-indicator-label {
white-space: nowrap;
max-width: 10rem;
overflow: hidden;
text-overflow: ellipsis;
}
/* Empty state */
.empty-state {
@apply flex-1 flex items-center justify-center p-12;
}
.empty-state-content {
@apply text-center max-w-sm;
}
.empty-state-content h3 {
font-size: var(--font-size-xl);
margin-bottom: 12px;
}
.empty-state-content p {
font-size: var(--font-size-base);
color: var(--text-muted);
margin-bottom: 16px;
}
.empty-state-content ul {
list-style: none;
padding: 0;
@apply flex flex-col gap-2;
}
.empty-state-content li {
font-size: var(--font-size-base);
color: var(--text-muted);
}
.empty-state-content code {
background-color: var(--surface-code);
padding: 2px 6px;
border-radius: 3px;
font-family: var(--font-family-mono);
font-size: 13px;
}
/* Loading state */
.loading-state {
@apply flex-1 flex flex-col items-center justify-center gap-4 p-12;
}
.spinner {
@apply w-8 h-8 border-2 border-t-transparent rounded-full;
border-color: var(--border-base);
border-top-color: var(--accent-primary);
animation: spin 1s linear infinite;
}
/* Modal utilities */
.modal-overlay {
@apply fixed inset-0 z-50;
background-color: var(--overlay-scrim);
}
.modal-surface {
@apply rounded-lg shadow-2xl flex flex-col;
background-color: var(--surface-base);
color: var(--text-primary);
}
.modal-search-container {
@apply p-4 border-b;
border-color: var(--border-base);
}
.modal-search-input {
@apply flex-1 bg-transparent outline-none;
color: var(--text-primary);
}
.modal-search-input::placeholder {
color: var(--text-muted);
}
.modal-search-icon {
color: var(--text-muted);
}
.modal-list-container {
@apply flex-1 overflow-y-auto;
}
.modal-section-header {
@apply px-4 py-2 text-xs font-semibold uppercase tracking-wide;
color: var(--text-muted);
}
.modal-item {
@apply w-full px-4 py-3 flex items-start gap-3 transition-colors cursor-pointer border-none text-left;
color: var(--text-primary);
}
.modal-list-container[data-pointer-mode="pointer"] .modal-item:hover {
background-color: var(--surface-hover);
}
.modal-list-container[data-pointer-mode="keyboard"] .modal-item:hover:not(.modal-item-highlight) {
background-color: inherit;
}
.modal-item-highlight {
background-color: var(--selection-highlight-bg);
}
.modal-item-label {
@apply font-medium;
color: var(--text-primary);
}
.modal-item-description {
@apply text-sm mt-0.5;
color: var(--text-secondary);
}
.modal-empty-state {
@apply p-8 text-center;
color: var(--text-muted);
}
/* Panel component utilities */
.panel {
@apply rounded-lg shadow-sm border overflow-hidden min-w-0;
background-color: var(--surface-base);
border-color: var(--border-base);
color: var(--text-primary);
}
.panel-footer-hints {
@apply flex items-center justify-center flex-wrap gap-3 text-xs;
color: var(--text-muted);
}
.panel-header {
@apply px-4 py-3 border-b;
border-color: var(--border-base);
background-color: var(--surface-secondary);
}
.panel-title {
@apply text-base font-semibold;
color: var(--text-primary);
}
.panel-subtitle {
@apply text-xs mt-0.5;
color: var(--text-muted);
}
.panel-body {
@apply p-4;
background-color: var(--surface-base);
}
.panel-section {
@apply border-t;
border-color: var(--border-base);
}
.panel-section-header {
@apply w-full px-4 py-3 flex items-center justify-center transition-colors cursor-pointer gap-2;
background-color: var(--surface-secondary);
}
.panel-section-header:hover {
background-color: var(--surface-hover);
}
.panel-section-content {
@apply px-4 py-3 border-t overflow-visible space-y-4 w-full;
border-color: var(--border-base);
background-color: var(--surface-secondary);
}
.panel-list {
@apply max-h-[400px] overflow-y-auto w-full min-w-0;
overflow-x: hidden;
}
.panel-list--fill {
max-height: none;
height: 100%;
}
.panel-list-item {
@apply border-b last:border-b-0 transition-colors w-full;
border-color: var(--border-base);
}
.panel-list-item:hover {
background-color: var(--surface-hover);
}
.panel-list-item-highlight {
background-color: var(--list-item-highlight-bg) !important;
box-shadow: inset 0 0 0 1px var(--list-item-highlight-border);
}
.panel-list-item-content {
@apply flex-1 text-left px-4 py-3 flex items-center justify-between gap-3 outline-none transition-colors w-full min-w-0;
}
.panel-list-item-content:hover {
background-color: transparent;
}
.panel-list-item-content:disabled {
opacity: 0.6;
}
.panel-list-item button:disabled {
cursor: not-allowed;
}
.panel-list-item-disabled {
opacity: 0.6;
}
.panel-empty-state {
@apply p-6 text-center;
}
.panel-empty-state-icon {
@apply text-gray-400 dark:text-gray-600 mb-2;
color: var(--text-muted);
}
.panel-empty-state-title {
@apply font-medium text-sm mb-1;
color: var(--text-secondary);
}
.panel-empty-state-description {
@apply text-xs;
color: var(--text-muted);
}
.panel-footer {
@apply px-4 py-3 border-t;
border-color: var(--border-base);
background-color: var(--surface-secondary);
}