From 941052acc847ecba02808d15677bbc20fc3e26a4 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Sat, 15 Nov 2025 20:47:19 +0000 Subject: [PATCH] modularize app styles --- src/styles/components/badges.css | 46 ++ src/styles/components/buttons.css | 56 +++ src/styles/components/dropdown.css | 72 ++++ src/styles/components/env-vars.css | 29 ++ src/styles/components/folder-loading.css | 32 ++ src/styles/components/selector.css | 252 +++++++++++ src/styles/controls.css | 503 +--------------------- src/styles/messaging.css | 7 +- src/styles/messaging/log-view.css | 74 ++++ src/styles/messaging/message-base.css | 98 +++++ src/styles/messaging/message-stream.css | 71 ++++ src/styles/messaging/prompt-input.css | 84 ++++ src/styles/messaging/tool-call.css | 518 +++++++++++++++++++++++ src/styles/panels.css | 12 +- src/styles/panels/empty-loading.css | 49 +++ src/styles/panels/modal.css | 70 +++ src/styles/panels/panel-shell.css | 121 ++++++ src/styles/panels/session-layout.css | 292 +++++++++++++ src/styles/panels/tabs.css | 110 +++++ 19 files changed, 1990 insertions(+), 506 deletions(-) create mode 100644 src/styles/components/badges.css create mode 100644 src/styles/components/buttons.css create mode 100644 src/styles/components/dropdown.css create mode 100644 src/styles/components/env-vars.css create mode 100644 src/styles/components/folder-loading.css create mode 100644 src/styles/components/selector.css create mode 100644 src/styles/messaging/log-view.css create mode 100644 src/styles/messaging/message-base.css create mode 100644 src/styles/messaging/message-stream.css create mode 100644 src/styles/messaging/prompt-input.css create mode 100644 src/styles/messaging/tool-call.css create mode 100644 src/styles/panels/empty-loading.css create mode 100644 src/styles/panels/modal.css create mode 100644 src/styles/panels/panel-shell.css create mode 100644 src/styles/panels/session-layout.css create mode 100644 src/styles/panels/tabs.css diff --git a/src/styles/components/badges.css b/src/styles/components/badges.css new file mode 100644 index 00000000..cf259faa --- /dev/null +++ b/src/styles/components/badges.css @@ -0,0 +1,46 @@ +/* Badge + status utilities */ +.neutral-badge { + @apply inline-flex items-center rounded px-1.5 py-0.5 text-xs font-normal; + background-color: var(--badge-neutral-bg); + color: var(--badge-neutral-text); +} + +.status-badge { + @apply inline-flex items-center gap-1.5 rounded px-2 py-1 text-xs font-medium; +} + +.status-badge.ready { + background-color: var(--status-ready-bg); + color: var(--status-ready-fg); +} + +.status-badge.starting { + background-color: var(--status-starting-bg); + color: var(--status-starting-fg); +} + +.status-badge.error { + background-color: var(--status-error-bg); + color: var(--status-error-fg); +} + +.status-badge.stopped { + background-color: var(--status-stopped-bg); + color: var(--status-stopped-fg); +} + +.status-dot.ready { + background-color: var(--status-ready-fg); +} + +.status-dot.starting { + background-color: var(--status-starting-fg); +} + +.status-dot.error { + background-color: var(--status-error-fg); +} + +.status-dot.stopped { + background-color: var(--status-stopped-fg); +} diff --git a/src/styles/components/buttons.css b/src/styles/components/buttons.css new file mode 100644 index 00000000..71c6c4c5 --- /dev/null +++ b/src/styles/components/buttons.css @@ -0,0 +1,56 @@ +/* Button component styles */ +.button-primary, +button.button-primary { + @apply px-6 py-3 text-base rounded-lg; + background-color: var(--button-primary-bg); + color: var(--button-primary-text); + border-color: var(--button-primary-bg); +} + +.button-primary:hover:not(:disabled), +button.button-primary:hover:not(:disabled) { + background-color: var(--button-primary-hover-bg); + border-color: var(--button-primary-hover-bg); +} + +.button-primary:focus-visible, +button.button-primary:focus-visible { + box-shadow: 0 0 0 2px var(--focus-ring-offset), 0 0 0 4px var(--focus-ring-color); +} + +.button-secondary, +button.button-secondary { + @apply px-6 py-3 text-base rounded-lg; + background-color: var(--surface-secondary); + color: var(--text-primary); + border-color: var(--border-base); +} + +.button-secondary:hover:not(:disabled), +button.button-secondary:hover:not(:disabled) { + background-color: var(--surface-hover); +} + +.button-secondary:focus-visible, +button.button-secondary:focus-visible { + box-shadow: 0 0 0 2px var(--focus-ring-offset), 0 0 0 4px var(--focus-ring-color); +} + +.button-tertiary, +button.button-tertiary { + @apply px-4 py-2 text-sm rounded-lg; + background-color: transparent; + color: var(--text-secondary); + border-color: var(--border-base); +} + +.button-tertiary:hover:not(:disabled), +button.button-tertiary:hover:not(:disabled) { + color: var(--text-primary); + background-color: var(--surface-hover); +} + +.button-tertiary:focus-visible, +button.button-tertiary:focus-visible { + box-shadow: 0 0 0 2px var(--focus-ring-offset), 0 0 0 4px var(--focus-ring-color); +} diff --git a/src/styles/components/dropdown.css b/src/styles/components/dropdown.css new file mode 100644 index 00000000..75bbf5c4 --- /dev/null +++ b/src/styles/components/dropdown.css @@ -0,0 +1,72 @@ +/* Dropdown utilities */ +.dropdown-surface { + @apply absolute w-full rounded-md shadow-lg z-50; + background-color: var(--surface-base); + border: 1px solid var(--border-base); +} + +.dropdown-header { + @apply px-3 py-2 border-b; + border-color: var(--border-base); + background-color: var(--surface-secondary); +} + +.dropdown-header-title { + @apply text-xs font-medium; + color: var(--text-muted); +} + +.dropdown-section-header { + @apply px-3 py-1.5 text-xs font-semibold; + color: var(--text-muted); + background-color: var(--surface-secondary); +} + +.dropdown-content { + @apply overflow-y-auto; +} + +.dropdown-item { + @apply cursor-pointer px-3 py-2 transition-colors; + color: var(--text-primary); +} + +.dropdown-item:hover { + background-color: var(--surface-hover); +} + +.dropdown-item-highlight { + background-color: var(--dropdown-highlight-bg); + color: var(--dropdown-highlight-text); +} + +.dropdown-empty { + @apply px-3 py-4 text-center text-sm; + color: var(--text-muted); +} + +.dropdown-loading { + @apply p-4 text-center text-sm; + color: var(--text-muted); +} + +.dropdown-footer { + @apply border-t px-3 py-2 text-xs; + border-color: var(--border-base); + color: var(--text-muted); +} + +.dropdown-badge { + @apply rounded px-1.5 py-0.5 text-xs font-normal; + background-color: var(--accent-primary); + color: var(--text-inverted); +} + +.dropdown-icon { + @apply flex-shrink-0; + color: var(--text-muted); +} + +.dropdown-icon-accent { + color: var(--accent-primary); +} diff --git a/src/styles/components/env-vars.css b/src/styles/components/env-vars.css new file mode 100644 index 00000000..6ca84d5b --- /dev/null +++ b/src/styles/components/env-vars.css @@ -0,0 +1,29 @@ +/* Environment variables display */ +.env-vars-container { + @apply px-4 py-3 border-b; + background-color: var(--env-vars-bg); + border-color: var(--env-vars-border); +} + +.env-vars-title { + @apply text-xs font-medium mb-2; + color: var(--env-vars-text); +} + +.env-var-item { + @apply flex items-center gap-2 text-xs; +} + +.env-var-key { + @apply font-mono font-medium min-w-0 flex-1; + color: var(--env-vars-text); +} + +.env-var-separator { + color: var(--env-vars-text); +} + +.env-var-value { + @apply font-mono min-w-0 flex-1; + color: var(--env-vars-text); +} diff --git a/src/styles/components/folder-loading.css b/src/styles/components/folder-loading.css new file mode 100644 index 00000000..d9769145 --- /dev/null +++ b/src/styles/components/folder-loading.css @@ -0,0 +1,32 @@ +/* Folder loading overlay */ +.folder-loading-overlay { + position: absolute; + inset: 0; + background-color: var(--folder-overlay-bg); + display: flex; + align-items: center; + justify-content: center; + z-index: 50; + backdrop-filter: blur(2px); +} + +.folder-loading-indicator { + @apply flex flex-col items-center gap-3 text-center; + padding: 24px 32px; + border-radius: var(--folder-card-radius); + background-color: var(--surface-base); + border: 1px solid var(--border-base); + box-shadow: var(--folder-card-shadow); + min-width: 260px; +} + +.folder-loading-text { + font-size: var(--font-size-lg); + font-weight: var(--font-weight-semibold); + color: var(--text-primary); +} + +.folder-loading-subtext { + font-size: var(--font-size-sm); + color: var(--text-secondary); +} diff --git a/src/styles/components/selector.css b/src/styles/components/selector.css new file mode 100644 index 00000000..c9bf3e82 --- /dev/null +++ b/src/styles/components/selector.css @@ -0,0 +1,252 @@ +/* Selector component utilities */ +.selector-trigger { + @apply inline-flex items-center justify-between gap-2 px-2 py-1 border rounded outline-none transition-colors text-xs min-w-[180px]; + background-color: var(--surface-base); + border-color: var(--border-base); + color: var(--text-primary); +} + +.selector-trigger:hover { + background-color: var(--surface-hover); +} + +.selector-trigger:focus { + @apply ring-2; + ring-color: var(--accent-primary); +} + +.selector-trigger-disabled { + @apply opacity-50 cursor-not-allowed; +} + +.selector-trigger-label { + @apply flex flex-col min-w-0; +} + +.selector-trigger-label--stacked { + @apply items-start; +} + +.selector-trigger-primary { + @apply text-sm font-medium truncate; + color: var(--text-primary); +} + +.selector-trigger-primary--align-left { + @apply text-left w-full; +} + +.selector-trigger-secondary { + @apply text-xs text-left truncate; + color: var(--text-muted); +} + +.selector-trigger-icon { + @apply flex-shrink-0; + color: var(--text-muted); +} + +.selector-popover { + @apply rounded-md shadow-lg overflow-hidden z-50 min-w-[300px]; + background-color: var(--surface-base); + border: 1px solid var(--border-base); +} + +.selector-search-container { + @apply p-2 border-b; + border-color: var(--border-base); +} + +.selector-search-input { + @apply w-full px-3 py-1.5 text-xs border rounded outline-none transition-colors; + background-color: var(--surface-base); + border-color: var(--border-base); + color: var(--text-primary); +} + +.selector-search-input:focus { + @apply ring-2; + ring-color: var(--accent-primary); +} + +.selector-search-input::placeholder { + color: var(--text-muted); +} + +.selector-listbox { + @apply max-h-64 overflow-auto p-1; + background-color: var(--surface-base); +} + +.selector-option { + @apply px-3 py-2 cursor-pointer rounded outline-none transition-colors flex items-start gap-2 w-full; + color: var(--text-primary); +} + +.selector-option:hover { + background-color: var(--surface-hover); +} + +.selector-option[data-highlighted], +.selector-option[data-focused] { + background-color: var(--selection-highlight-bg); +} + +.selector-option[data-selected], +.selector-option-selected { + background-color: var(--selection-highlight-strong-bg); +} + +.selector-option-content { + @apply flex flex-col flex-1 min-w-0; +} + +.selector-option-label { + @apply font-medium text-sm; + color: var(--text-primary); +} + +.selector-option-description { + @apply text-xs; + color: var(--text-muted); +} + +.selector-option .remove-binary-button { + opacity: 0; +} + +.selector-option:hover .remove-binary-button { + opacity: 1; +} + +.remove-binary-button { + @apply p-1 rounded transition-all; + color: var(--text-muted); +} + +.remove-binary-button:hover { + background-color: var(--danger-soft-bg); + color: var(--status-error); +} + +.selector-option-indicator { + @apply flex-shrink-0 mt-0.5; + color: var(--accent-primary); +} + +.selector-section { + @apply px-3 py-2 border-b; + border-color: var(--border-base); + background-color: var(--surface-secondary); +} + +.selector-section-title { + @apply text-xs font-medium; + color: var(--text-muted); +} + +.selector-badge { + @apply rounded px-1.5 py-0.5 text-xs font-normal; + background-color: var(--accent-primary); + color: var(--text-inverted); +} + +.selector-badge-version { + @apply text-xs; + color: var(--text-muted); +} + +.selector-badge-time { + @apply text-xs; + color: var(--text-muted); +} + +.selector-validation-error { + @apply p-2 rounded border; + background-color: var(--message-error-bg); + border-color: var(--status-error); + color: var(--status-error); +} + +.selector-validation-error-content { + @apply flex items-start gap-2; +} + +.selector-validation-error-icon { + @apply w-4 h-4 mt-0.5 flex-shrink-0; + color: var(--status-error); +} + +.selector-validation-error-text { + @apply text-xs; +} + +.selector-input-group { + @apply flex gap-2; +} + +.selector-input { + @apply flex-1 px-2 py-1.5 text-sm border rounded outline-none transition-colors; + background-color: var(--surface-base); + border-color: var(--border-base); + color: var(--text-primary); +} + +.selector-input:focus { + @apply ring-1; + ring-color: var(--accent-primary); +} + +.selector-input::placeholder { + color: var(--text-muted); +} + +.selector-button { + @apply px-3 py-1.5 text-sm rounded transition-colors cursor-pointer w-full inline-flex items-center justify-center font-medium; + background-color: var(--surface-secondary); + color: var(--text-primary); + border: 1px solid var(--border-base); +} + +.selector-button-primary { + background-color: var(--accent-primary) !important; + color: var(--text-inverted) !important; + border: 1px solid var(--accent-primary) !important; +} + +.selector-button-primary:hover:not(:disabled) { + background-color: var(--accent-hover); +} + +.selector-button-primary:disabled { + @apply opacity-50 cursor-not-allowed; + background-color: var(--surface-muted); +} + +.selector-button-secondary { + background-color: var(--surface-secondary); + color: var(--text-primary); +} + +.selector-button-secondary:hover:not(:disabled) { + background-color: var(--surface-hover); +} + +.selector-button-secondary:disabled { + @apply opacity-50 cursor-not-allowed; +} + +.selector-empty-state { + @apply p-4 text-center text-sm; + color: var(--text-muted); +} + +.selector-loading { + @apply flex items-center gap-2; + color: var(--text-muted); +} + +.selector-loading-spinner { + @apply w-4 h-4 animate-spin; + color: var(--accent-primary); +} diff --git a/src/styles/controls.css b/src/styles/controls.css index fd74f0ac..d70d648d 100644 --- a/src/styles/controls.css +++ b/src/styles/controls.css @@ -1,497 +1,6 @@ -@import "./tokens.css"; -@import "./utilities.css"; - -.button-primary, -button.button-primary { - @apply px-6 py-3 text-base rounded-lg; - background-color: var(--button-primary-bg); - color: var(--button-primary-text); - border-color: var(--button-primary-bg); -} - -.button-primary:hover:not(:disabled), -button.button-primary:hover:not(:disabled) { - background-color: var(--button-primary-hover-bg); - border-color: var(--button-primary-hover-bg); -} - -.button-primary:focus-visible, -button.button-primary:focus-visible { - box-shadow: 0 0 0 2px var(--focus-ring-offset), 0 0 0 4px var(--focus-ring-color); -} - -.button-secondary, -button.button-secondary { - @apply px-6 py-3 text-base rounded-lg; - background-color: var(--surface-secondary); - color: var(--text-primary); - border-color: var(--border-base); -} - -.button-secondary:hover:not(:disabled), -button.button-secondary:hover:not(:disabled) { - background-color: var(--surface-hover); -} - -.button-secondary:focus-visible, -button.button-secondary:focus-visible { - box-shadow: 0 0 0 2px var(--focus-ring-offset), 0 0 0 4px var(--focus-ring-color); -} - -.button-tertiary, -button.button-tertiary { - @apply px-4 py-2 text-sm rounded-lg; - background-color: transparent; - color: var(--text-secondary); - border-color: var(--border-base); -} - -.button-tertiary:hover:not(:disabled), -button.button-tertiary:hover:not(:disabled) { - color: var(--text-primary); - background-color: var(--surface-hover); -} - -.button-tertiary:focus-visible, -button.button-tertiary:focus-visible { - box-shadow: 0 0 0 2px var(--focus-ring-offset), 0 0 0 4px var(--focus-ring-color); -} - -/* Neutral badge utilities */ -.neutral-badge { - @apply inline-flex items-center rounded px-1.5 py-0.5 text-xs font-normal; - background-color: var(--badge-neutral-bg); - color: var(--badge-neutral-text); -} - -/* Status badge utilities */ -.status-badge { - @apply inline-flex items-center gap-1.5 rounded px-2 py-1 text-xs font-medium; -} - -.status-badge.ready { - background-color: var(--status-ready-bg); - color: var(--status-ready-fg); -} - -.status-badge.starting { - background-color: var(--status-starting-bg); - color: var(--status-starting-fg); -} - -.status-badge.error { - background-color: var(--status-error-bg); - color: var(--status-error-fg); -} - -.status-badge.stopped { - background-color: var(--status-stopped-bg); - color: var(--status-stopped-fg); -} - -.status-dot.ready { - background-color: var(--status-ready-fg); -} - -.status-dot.starting { - background-color: var(--status-starting-fg); -} - -.status-dot.error { - background-color: var(--status-error-fg); -} - -.status-dot.stopped { - background-color: var(--status-stopped-fg); -} - -.folder-loading-overlay { - position: absolute; - inset: 0; - background-color: var(--folder-overlay-bg); - display: flex; - align-items: center; - justify-content: center; - z-index: 50; - backdrop-filter: blur(2px); -} - -.folder-loading-indicator { - @apply flex flex-col items-center gap-3 text-center; - padding: 24px 32px; - border-radius: var(--folder-card-radius); - background-color: var(--surface-base); - border: 1px solid var(--border-base); - box-shadow: var(--folder-card-shadow); - min-width: 260px; -} - -.folder-loading-text { - font-size: var(--font-size-lg); - font-weight: var(--font-weight-semibold); - color: var(--text-primary); -} - -.folder-loading-subtext { - font-size: var(--font-size-sm); - color: var(--text-secondary); -} - -/* Dropdown utilities */ -.dropdown-surface { - @apply absolute w-full rounded-md shadow-lg z-50; - background-color: var(--surface-base); - border: 1px solid var(--border-base); -} - -.dropdown-header { - @apply px-3 py-2 border-b; - border-color: var(--border-base); - background-color: var(--surface-secondary); -} - -.dropdown-header-title { - @apply text-xs font-medium; - color: var(--text-muted); -} - -.dropdown-section-header { - @apply px-3 py-1.5 text-xs font-semibold; - color: var(--text-muted); - background-color: var(--surface-secondary); -} - -.dropdown-content { - @apply overflow-y-auto; -} - -.dropdown-item { - @apply cursor-pointer px-3 py-2 transition-colors; - color: var(--text-primary); -} - -.dropdown-item:hover { - background-color: var(--surface-hover); -} - -.dropdown-item-highlight { - background-color: var(--dropdown-highlight-bg); - color: var(--dropdown-highlight-text); -} - - -.dropdown-empty { - @apply px-3 py-4 text-center text-sm; - color: var(--text-muted); -} - -.dropdown-loading { - @apply p-4 text-center text-sm; - color: var(--text-muted); -} - -.dropdown-footer { - @apply border-t px-3 py-2 text-xs; - border-color: var(--border-base); - color: var(--text-muted); -} - -.dropdown-badge { - @apply rounded px-1.5 py-0.5 text-xs font-normal; - background-color: var(--accent-primary); - color: var(--text-inverted); -} - -.dropdown-icon { - @apply flex-shrink-0; - color: var(--text-muted); -} - -.dropdown-icon-accent { - color: var(--accent-primary); -} - -/* Selector component utilities */ - -.selector-trigger { - @apply inline-flex items-center justify-between gap-2 px-2 py-1 border rounded outline-none transition-colors text-xs min-w-[180px]; - background-color: var(--surface-base); - border-color: var(--border-base); - color: var(--text-primary); -} - -.selector-trigger:hover { - background-color: var(--surface-hover); -} - -.selector-trigger:focus { - @apply ring-2; - ring-color: var(--accent-primary); -} - -.selector-trigger-disabled { - @apply opacity-50 cursor-not-allowed; -} - -.selector-trigger-label { - @apply flex flex-col min-w-0; -} - -.selector-trigger-label--stacked { - @apply items-start; -} - -.selector-trigger-primary { - @apply text-sm font-medium truncate; - color: var(--text-primary); -} - -.selector-trigger-primary--align-left { - @apply text-left w-full; -} - -.selector-trigger-secondary { - @apply text-xs text-left truncate; - color: var(--text-muted); -} - -.selector-trigger-icon { - @apply flex-shrink-0; - color: var(--text-muted); -} - -.selector-popover { - @apply rounded-md shadow-lg overflow-hidden z-50 min-w-[300px]; - background-color: var(--surface-base); - border: 1px solid var(--border-base); -} - -.selector-search-container { - @apply p-2 border-b; - border-color: var(--border-base); -} - -.selector-search-input { - @apply w-full px-3 py-1.5 text-xs border rounded outline-none transition-colors; - background-color: var(--surface-base); - border-color: var(--border-base); - color: var(--text-primary); -} - -.selector-search-input:focus { - @apply ring-2; - ring-color: var(--accent-primary); -} - -.selector-search-input::placeholder { - color: var(--text-muted); -} - -.selector-listbox { - @apply max-h-64 overflow-auto p-1; - background-color: var(--surface-base); -} - -.selector-option { - @apply px-3 py-2 cursor-pointer rounded outline-none transition-colors flex items-start gap-2 w-full; - color: var(--text-primary); -} - -.selector-option:hover { - background-color: var(--surface-hover); -} - -.selector-option[data-highlighted], -.selector-option[data-focused] { - background-color: var(--selection-highlight-bg); -} - -.selector-option[data-selected], -.selector-option-selected { - background-color: var(--selection-highlight-strong-bg); -} - -.selector-option-content { - @apply flex flex-col flex-1 min-w-0; -} - -.selector-option-label { - @apply font-medium text-sm; - color: var(--text-primary); -} - -.selector-option-description { - @apply text-xs; - color: var(--text-muted); -} - -.selector-option .remove-binary-button { - opacity: 0; -} - -.selector-option:hover .remove-binary-button { - opacity: 1; -} - -.remove-binary-button { - @apply p-1 rounded transition-all; - color: var(--text-muted); -} - -.remove-binary-button:hover { - background-color: var(--danger-soft-bg); - color: var(--status-error); -} - -.selector-option-indicator { - @apply flex-shrink-0 mt-0.5; - color: var(--accent-primary); -} - -.selector-section { - @apply px-3 py-2 border-b; - border-color: var(--border-base); - background-color: var(--surface-secondary); -} - -.selector-section-title { - @apply text-xs font-medium; - color: var(--text-muted); -} - -.selector-badge { - @apply rounded px-1.5 py-0.5 text-xs font-normal; - background-color: var(--accent-primary); - color: var(--text-inverted); -} - -.selector-badge-version { - @apply text-xs; - color: var(--text-muted); -} - -.selector-badge-time { - @apply text-xs; - color: var(--text-muted); -} - -.selector-validation-error { - @apply p-2 rounded border; - background-color: var(--message-error-bg); - border-color: var(--status-error); - color: var(--status-error); -} - -.selector-validation-error-content { - @apply flex items-start gap-2; -} - -.selector-validation-error-icon { - @apply w-4 h-4 mt-0.5 flex-shrink-0; - color: var(--status-error); -} - -.selector-validation-error-text { - @apply text-xs; -} - -.selector-input-group { - @apply flex gap-2; -} - -.selector-input { - @apply flex-1 px-2 py-1.5 text-sm border rounded outline-none transition-colors; - background-color: var(--surface-base); - border-color: var(--border-base); - color: var(--text-primary); -} - -.selector-input:focus { - @apply ring-1; - ring-color: var(--accent-primary); -} - -.selector-input::placeholder { - color: var(--text-muted); -} - -.selector-button { - @apply px-3 py-1.5 text-sm rounded transition-colors cursor-pointer w-full inline-flex items-center justify-center font-medium; - background-color: var(--surface-secondary); - color: var(--text-primary); - border: 1px solid var(--border-base); -} - -.selector-button-primary { - background-color: var(--accent-primary) !important; - color: var(--text-inverted) !important; - border: 1px solid var(--accent-primary) !important; -} - -.selector-button-primary:hover:not(:disabled) { - background-color: var(--accent-hover); -} - -.selector-button-primary:disabled { - @apply opacity-50 cursor-not-allowed; - background-color: var(--surface-muted); -} - -.selector-button-secondary { - background-color: var(--surface-secondary); - color: var(--text-primary); -} - -.selector-button-secondary:hover:not(:disabled) { - background-color: var(--surface-hover); -} - -.selector-button-secondary:disabled { - @apply opacity-50 cursor-not-allowed; -} - -.selector-empty-state { - @apply p-4 text-center text-sm; - color: var(--text-muted); -} - -.selector-loading { - @apply flex items-center gap-2; - color: var(--text-muted); -} - -.selector-loading-spinner { - @apply w-4 h-4 animate-spin; - color: var(--accent-primary); -} - -/* Environment variables display */ -.env-vars-container { - @apply px-4 py-3 border-b; - background-color: var(--env-vars-bg); - border-color: var(--env-vars-border); -} - -.env-vars-title { - @apply text-xs font-medium mb-2; - color: var(--env-vars-text); -} - -.env-var-item { - @apply flex items-center gap-2 text-xs; -} - -.env-var-key { - @apply font-mono font-medium min-w-0 flex-1; - color: var(--env-vars-text); -} - -.env-var-separator { - color: var(--env-vars-text); -} - -.env-var-value { - @apply font-mono min-w-0 flex-1; - color: var(--env-vars-text); -} - +@import "./components/buttons.css"; +@import "./components/badges.css"; +@import "./components/folder-loading.css"; +@import "./components/dropdown.css"; +@import "./components/selector.css"; +@import "./components/env-vars.css"; diff --git a/src/styles/messaging.css b/src/styles/messaging.css index 66553001..4b55bc5f 100644 --- a/src/styles/messaging.css +++ b/src/styles/messaging.css @@ -1,5 +1,8 @@ -@import "./tokens.css"; -@import "./utilities.css"; +@import "./messaging/message-base.css"; +@import "./messaging/prompt-input.css"; +@import "./messaging/message-stream.css"; +@import "./messaging/tool-call.css"; +@import "./messaging/log-view.css"; /* Message item base styles */ diff --git a/src/styles/messaging/log-view.css b/src/styles/messaging/log-view.css new file mode 100644 index 00000000..6f362364 --- /dev/null +++ b/src/styles/messaging/log-view.css @@ -0,0 +1,74 @@ +/* Log view utilities */ +.log-container { + @apply flex flex-col h-full; + background-color: var(--surface-base); +} + +.log-header { + @apply flex items-center justify-between px-4 py-3 border-b; + border-color: var(--border-base); + background-color: var(--surface-secondary); +} + +.log-content { + @apply flex-1 overflow-y-auto p-4 font-mono text-xs leading-relaxed; + background-color: var(--surface-secondary); + color: var(--text-primary); +} + +.log-entry { + @apply flex gap-3 py-0.5 px-2 -mx-2 rounded transition-colors; +} + +.log-entry:hover { + background-color: var(--surface-hover); +} + +.log-timestamp { + @apply select-none shrink-0; + color: var(--text-muted); +} + +.log-message { + @apply break-all; +} + +.log-level-error { + color: var(--log-level-error); +} + +.log-level-warn { + color: var(--log-level-warn); +} + +.log-level-debug { + color: var(--log-level-debug); +} + +.log-level-default { + color: var(--log-level-default); +} + +.log-empty-state { + @apply text-center py-8; + color: var(--text-muted); +} + +.log-paused-state { + @apply flex flex-col items-center justify-center gap-3 text-center py-10 px-6; + border: 1px dashed var(--border-base); + border-radius: 12px; + background-color: var(--surface-base); +} + +.log-paused-title { + font-size: var(--font-size-base); + font-weight: var(--font-weight-semibold); + color: var(--text-primary); +} + +.log-paused-description { + font-size: var(--font-size-sm); + color: var(--text-secondary); + max-width: 320px; +} diff --git a/src/styles/messaging/message-base.css b/src/styles/messaging/message-base.css new file mode 100644 index 00000000..b43c1543 --- /dev/null +++ b/src/styles/messaging/message-base.css @@ -0,0 +1,98 @@ +/* Message item base styles */ +.message-item-base { + @apply flex flex-col gap-2 p-3 w-full; +} + +.assistant-message { + /* gap: 0.25rem; */ + padding: 0.6rem 0.65rem; +} + +.message-queued-badge { + @apply inline-block font-bold px-3 py-1 rounded mb-3 text-xs tracking-wide; + background-color: var(--accent-primary); + color: var(--text-inverted); +} + +.message-error-block { + @apply text-sm p-3 rounded border-l-[3px] my-2; + color: var(--status-error); + background-color: var(--message-error-bg); + border-color: var(--status-error); +} + +.message-generating { + @apply text-sm italic py-2; + color: var(--text-muted); +} + +.message-sending { + @apply text-xs italic mt-1; + color: var(--text-muted); +} + +.message-error { + @apply text-xs mt-1; + color: var(--status-error); +} + +.generating-spinner { + @apply inline-block; + animation: pulse 1.5s ease-in-out infinite; +} + +.message-text { + font-size: var(--font-size-base); + line-height: var(--line-height-normal); + word-wrap: break-word; + overflow-wrap: break-word; + color: inherit; +} + +.message-text-assistant { + white-space: normal; +} + +.message-text pre { + overflow-x: auto; + padding: 8px; + background-color: var(--surface-code); + border-radius: 4px; +} + +.message-error-part { + color: var(--status-error); + font-size: var(--font-size-base); + padding: 8px; + background-color: var(--message-error-bg); + border-radius: 4px; +} + +.message-reasoning { + @apply my-2 border rounded; + border-color: var(--border-base); + background-color: var(--surface-secondary); + color: inherit; +} + +.reasoning-container { + @apply p-2; +} + +.reasoning-header { + @apply flex items-center gap-1.5 text-xs cursor-pointer select-none; + color: var(--text-muted); +} + +.reasoning-header:hover { + color: var(--accent-primary); +} + +.reasoning-icon { + @apply text-xs; + transition: transform 150ms ease; +} + +.reasoning-label { + font-weight: var(--font-weight-medium); +} diff --git a/src/styles/messaging/message-stream.css b/src/styles/messaging/message-stream.css new file mode 100644 index 00000000..d1ad0a55 --- /dev/null +++ b/src/styles/messaging/message-stream.css @@ -0,0 +1,71 @@ +/* Message stream container + status */ +.message-stream-container { + @apply relative flex-1 min-h-0 flex flex-col overflow-hidden; +} + +.connection-status { + @apply grid items-center px-4 py-2 gap-4; + grid-template-columns: 1fr auto 1fr; + background-color: var(--surface-secondary); + border-bottom: 1px solid var(--border-base); +} + +.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); +} + +.message-stream { + @apply flex-1 min-h-0 overflow-y-auto flex flex-col gap-1; + background-color: var(--surface-base); + color: inherit; +} + +.message-scroll-button-wrapper { + position: absolute; + right: 1rem; + bottom: 1rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + align-items: flex-end; +} + +.message-scroll-button { + @apply inline-flex items-center justify-center; + width: 2.75rem; + height: 2.75rem; + border-radius: 9999px; + border: 1px solid var(--border-base); + background-color: transparent; + color: var(--text-primary); + box-shadow: var(--scroll-elevation-shadow); + transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease; +} + +.message-scroll-button:hover { + background-color: var(--surface-hover); + transform: translateY(-1px); +} + +.message-scroll-button:focus-visible { + outline: none; + box-shadow: 0 0 0 2px var(--surface-base), 0 0 0 4px var(--accent-primary); +} + +.message-scroll-icon { + font-size: var(--font-size-lg); + color: var(--accent-primary); +} diff --git a/src/styles/messaging/prompt-input.css b/src/styles/messaging/prompt-input.css new file mode 100644 index 00000000..8a1680fa --- /dev/null +++ b/src/styles/messaging/prompt-input.css @@ -0,0 +1,84 @@ +/* Prompt input & attachment styles */ +.prompt-input-container { + @apply flex flex-col border-t; + border-color: var(--border-base); + background-color: var(--surface-base); +} + +.prompt-input-wrapper { + @apply flex items-end gap-2 p-3; +} + +.prompt-input { + @apply flex-1 min-h-[96px] max-h-[200px] p-2.5 border rounded-md text-sm resize-none outline-none transition-colors; + font-family: inherit; + background-color: var(--surface-base); + color: inherit; + border-color: var(--border-base); + line-height: var(--line-height-normal); +} + +.prompt-input:focus { + border-color: var(--accent-primary); +} + +.prompt-input:disabled { + @apply opacity-60 cursor-not-allowed; +} + +.prompt-input::placeholder { + color: var(--text-muted); +} + +.send-button { + @apply w-10 h-10 rounded-md border-none cursor-pointer flex items-center justify-center transition-all flex-shrink-0; + background-color: var(--accent-primary); + color: var(--text-inverted); +} + +.send-button:hover:not(:disabled) { + @apply opacity-90 scale-105; +} + +.send-button:active:not(:disabled) { + @apply scale-95; +} + +.send-button:disabled { + @apply opacity-40 cursor-not-allowed; +} + +.send-icon { + @apply text-base; +} + +.prompt-input-hints { + @apply px-4 pb-2 flex justify-between items-center; +} + +.hint { + @apply text-xs; + color: var(--text-muted); +} + +.hint kbd { + @apply inline-block px-1.5 py-0.5 text-xs font-mono rounded mx-0.5; + background-color: var(--surface-secondary); + border: 1px solid var(--border-base); + border-radius: 3px; +} + +.attachment-chip { + @apply px-2.5 py-1 text-xs font-medium ring-1 ring-inset; + background-color: var(--attachment-chip-bg); + color: var(--attachment-chip-text); + ring-color: var(--attachment-chip-ring); +} + +.attachment-remove { + @apply ml-0.5 flex h-4 w-4 items-center justify-center rounded transition-colors; +} + +.attachment-remove:hover { + background-color: var(--attachment-chip-ring); +} diff --git a/src/styles/messaging/tool-call.css b/src/styles/messaging/tool-call.css new file mode 100644 index 00000000..061eec78 --- /dev/null +++ b/src/styles/messaging/tool-call.css @@ -0,0 +1,518 @@ +/* Tool call rendering */ +.tool-call-message { + @apply flex flex-col gap-2 p-3 w-full; + background-color: var(--message-tool-bg); + border-left: 4px solid var(--message-tool-border); + color: inherit; +} + +.tool-call-header-label { + @apply flex items-center justify-between gap-2 font-semibold text-sm; + color: var(--message-tool-border); + margin-bottom: 1px; +} + +.tool-call-header-meta { + @apply flex items-center gap-2; +} + +.tool-call-header-button { + background-color: transparent; + border: 1px solid var(--border-base); + color: var(--message-tool-border); + padding: 0.15rem 0.75rem; + border-radius: 0.375rem; + font-size: 0.75rem; + font-weight: var(--font-weight-semibold); + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; + height: 1.5rem; + transition: all 0.2s ease; +} + +.tool-call-header-button:hover:not(:disabled) { + background-color: var(--surface-hover); + border-color: var(--accent-primary); + color: var(--accent-primary); +} + +.tool-call-header-button:active:not(:disabled) { + transform: scale(0.95); +} + +.tool-call-header-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.tool-call-header-label .tool-call-icon { + @apply text-base; +} + +.tool-call-header-label .tool-name { + font-family: var(--font-family-mono); + color: inherit; + background-color: var(--surface-secondary); + border: 1px solid var(--border-base); + padding: 2px 6px; + border-radius: 3px; + font-size: 13px; +} + +.tool-call { + @apply border overflow-hidden; + border-color: var(--border-base); + color: inherit; + --tool-call-line-unit: 1.4em; + --tool-call-lines-compact: 24; + --tool-call-lines-large: 48; + --tool-call-max-height-compact: calc(var(--tool-call-lines-compact) * var(--tool-call-line-unit)); + --tool-call-max-height-large: calc(var(--tool-call-lines-large) * var(--tool-call-line-unit)); +} + +.tool-call-message .tool-call { + border: none; + border-radius: 0; + margin: 0; +} + +.tool-call-header { + @apply flex items-center gap-2 p-2 w-full bg-transparent border-none cursor-pointer text-left; + font-family: var(--font-family-mono); + font-size: 13px; + border-radius: 0; +} + +.tool-call-header:hover { + background-color: var(--surface-hover); +} + +.tool-call-icon { + @apply text-xs; +} + +.tool-call-summary { + @apply flex-1 text-left; +} + +.tool-call-status { + @apply text-sm; +} + +.tool-call-status-success { + border-left: 3px solid var(--status-success); +} + +.tool-call-status-error { + border-left: 3px solid var(--status-error); +} + +.tool-call-status-running { + border-left: 3px solid var(--status-warning); +} + +.tool-call-status-running .tool-call-status { + animation: pulse 1.5s ease-in-out infinite; +} + +.tool-call-status-pending { + border-left: 3px solid var(--accent-primary); +} + +.tool-call-status-pending .tool-call-summary { + animation: shimmer 2s ease-in-out infinite; +} + +.tool-call-preview { + @apply p-2 flex flex-col gap-1.5; + background-color: var(--surface-code); + border-top: 1px solid var(--border-base); +} + +.tool-call-preview-label { + @apply text-xs font-semibold uppercase tracking-wide; + color: var(--text-muted); + letter-spacing: 0.5px; +} + +.tool-call-preview-text { + font-family: var(--font-family-mono); + font-size: var(--font-size-xs); + line-height: var(--line-height-tight); + color: var(--text-muted); + white-space: pre-wrap; + word-wrap: break-word; + overflow-wrap: break-word; + max-height: var(--tool-call-max-height-compact, calc(25 * 1.4em)); + overflow-y: scroll; +} + +.tool-call-details { + @apply flex flex-col; + background-color: var(--surface-code); + font-size: var(--font-size-xs); +} + +.tool-call-markdown { + background-color: var(--surface-code); + border: none; + border-radius: 0; + padding: 0; + font-size: var(--font-size-xs); + line-height: var(--line-height-tight); + max-height: var(--tool-call-max-height-compact, calc(25 * 1.4em)); + overflow-y: scroll; + scrollbar-width: thin; + scrollbar-color: var(--border-base) transparent; + scrollbar-gutter: stable both-edges; + position: relative; +} + +.tool-call-markdown-large { + max-height: var(--tool-call-max-height-large, calc(48 * 1.4em)); +} + +.tool-call-diff-shell { + padding: 0; +} + +.tool-call-diff-viewer { + max-height: var(--tool-call-max-height-large, calc(48 * 1.4em)); + overflow: auto; + background-color: var(--surface-code); +} + +.tool-call-diff-toolbar { + @apply flex items-center justify-between gap-3 px-3 py-2; + background-color: var(--surface-secondary); + border-bottom: 1px solid var(--border-base); +} + +.tool-call-diff-toolbar-label { + font-size: 11px; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.08em; +} + +.tool-call-diff-toggle { + @apply inline-flex items-center gap-1; +} + +.tool-call-diff-mode-button { + @apply border text-xs font-semibold px-3 py-1 rounded transition-all duration-150; + border-color: var(--border-base); + background-color: transparent; + color: var(--text-muted); +} + +.tool-call-diff-mode-button:hover { + background-color: var(--surface-hover); + color: var(--text-primary); +} + +.tool-call-diff-mode-button.active { + background-color: var(--accent-primary); + border-color: var(--accent-primary); + color: var(--text-inverted); +} + +.tool-call-diff-viewer .diff-tailwindcss-wrapper { + background-color: transparent; + color: inherit; +} + +.tool-call-diff-viewer .diff-view-wrapper { + font-family: var(--font-family-mono); +} + +.tool-call-diff-fallback { + margin: 0; + padding: 0.75rem; + background-color: var(--surface-code); + font-family: var(--font-family-mono); + font-size: var(--font-size-xs); + line-height: var(--line-height-tight); +} + +.tool-call-diff-viewer .diff-line-old-num, +.tool-call-diff-viewer .diff-line-new-num, +.tool-call-diff-viewer .diff-line-num { + width: auto !important; + min-width: 4ch; + padding-left: 0.5rem; + padding-right: 0.5rem; + white-space: nowrap; +} + +.tool-call-markdown .markdown-code-block { + margin: 0; + border: none; + background-color: transparent; +} + +.tool-call-markdown .code-block-header { + position: sticky; + top: 0; + z-index: auto; + box-shadow: 0 1px 0 var(--border-base); +} + +.tool-call-markdown .markdown-code-block pre { + margin: 0 !important; + min-height: auto; + max-height: none; + overflow-y: visible; +} + +.tool-call-markdown::-webkit-scrollbar { + width: 8px; +} + +.tool-call-markdown::-webkit-scrollbar-track { + background: transparent; +} + +.tool-call-markdown::-webkit-scrollbar-thumb { + background-color: var(--border-base); + border-radius: 4px; + border: 2px solid transparent; + background-clip: padding-box; +} + +.tool-call-section h4 { + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + margin-bottom: 4px; + color: var(--text-muted); +} + +.tool-call-section pre { + margin: 0; + padding: 8px; + background-color: var(--surface-base); + border-radius: 0px; + overflow-x: auto; + max-height: var(--tool-call-max-height-compact, calc(25 * 1.4em)); + overflow-y: scroll; +} + +.tool-call-section code { + font-family: var(--font-family-mono); + font-size: var(--font-size-xs); + line-height: var(--line-height-tight); +} + +.tool-call-section pre::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +.tool-call-section pre::-webkit-scrollbar-track { + background: var(--surface-secondary); + border-radius: 0px; +} + +.tool-call-section pre::-webkit-scrollbar-thumb { + background: var(--border-base); + border-radius: 0px; +} + +.tool-call-section pre::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} + +.tool-call-pending-message { + @apply flex items-center gap-2 p-3 text-xs italic; + color: var(--text-muted); +} + +.tool-call-emoji { + @apply text-base mr-1; +} + +.tool-call-action-button { + @apply border text-xs font-semibold px-3 py-1 rounded transition-colors h-8 flex items-center; + border-color: var(--border-base); + color: var(--text-muted); + background-color: transparent; +} + +.tool-call-action-button:hover:not(:disabled) { + background-color: var(--surface-hover); + color: var(--text-primary); +} + +.tool-call-action-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.tool-call-bash, +.tool-call-diff { + @apply my-2; +} + +.tool-call-content { + background-color: var(--surface-secondary); + border: 1px solid var(--border-base); + border-radius: 0; + padding: 8px 12px; + font-family: var(--font-family-mono); + font-size: var(--font-size-xs); + line-height: var(--line-height-tight); + overflow-x: auto; + margin: 0; +} + +.tool-call-content code { + font-family: inherit; + background: none; + padding: 0; + font-size: inherit; +} + +.tool-call-todos { + @apply my-2 flex flex-col gap-2; + list-style: none; + padding: 4px 0; +} + +.tool-call-todo-item { + @apply flex items-start gap-3; + border: 1px solid var(--border-base); + border-radius: 8px; + padding: 10px 12px; + background-color: var(--surface-secondary); +} + +.tool-call-todo-item-completed { + background-color: var(--surface-code); +} + +.tool-call-todo-item-active { + border-color: var(--accent-primary); + background-color: var(--surface-hover); +} + +.tool-call-todo-item-cancelled { + opacity: 0.75; +} + +.tool-call-todo-checkbox { + width: 1.1rem; + height: 1.1rem; + border-radius: 9999px; + border: 2px solid var(--border-base); + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + font-weight: var(--font-weight-semibold); + color: var(--text-muted); + background-color: transparent; +} + +.tool-call-todo-checkbox::after { + content: ""; + line-height: 1; +} + +.tool-call-todo-checkbox[data-status="completed"] { + background-color: var(--accent-primary); + border-color: var(--accent-primary); + color: var(--text-inverted); +} + +.tool-call-todo-checkbox[data-status="completed"]::after { + content: "✓"; +} + +.tool-call-todo-checkbox[data-status="in_progress"]::after { + content: "…"; + color: var(--accent-primary); +} + +.tool-call-todo-checkbox[data-status="cancelled"]::after { + content: "×"; + color: var(--status-error); +} + +.tool-call-todo-body { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; +} + +.tool-call-todo-text { + font-size: var(--font-size-sm); + line-height: var(--line-height-tight); + color: var(--text-primary); +} + +.tool-call-todo-item-cancelled .tool-call-todo-text { + text-decoration: line-through; + color: var(--text-muted); +} + +.tool-call-todo-tag { + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.08em; + border-radius: 9999px; + padding: 2px 8px; + background-color: var(--surface-hover); + color: var(--text-muted); +} + +.tool-call-todo-item-active .tool-call-todo-tag { + background-color: var(--accent-primary); + color: var(--text-inverted); +} + +.tool-call-task-container { + padding: 12px; +} + +.tool-call-task-summary { + @apply my-2 flex flex-col gap-1.5; +} + +.tool-call-task-item { + font-size: var(--font-size-xs); + line-height: var(--line-height-normal); + padding-left: 8px; + border-left: 2px solid var(--border-base); +} + +.tool-call-task-item::before { + content: "∟ "; + color: var(--text-muted); +} + +.tool-call-error-content { + background-color: var(--message-error-bg); + border-left: 3px solid var(--status-error); + padding: 12px; + margin: 8px 0; + border-radius: 4px; + color: var(--status-error); + font-size: var(--font-size-xs); +} + +.tool-call-error-content strong { + font-weight: var(--font-weight-semibold); +} + +.dropdown-diff-added { + @apply text-xs; + color: var(--status-success); +} + +.dropdown-diff-removed { + @apply text-xs; + color: var(--status-error); +} diff --git a/src/styles/panels.css b/src/styles/panels.css index 81cf7f5f..536cdd70 100644 --- a/src/styles/panels.css +++ b/src/styles/panels.css @@ -1,11 +1,9 @@ -@import "./tokens.css"; -@import "./utilities.css"; +@import "./panels/tabs.css"; +@import "./panels/empty-loading.css"; +@import "./panels/modal.css"; +@import "./panels/panel-shell.css"; +@import "./panels/session-layout.css"; -/* Tab component utilities */ -.tab-bar { - @apply border-b; - border-color: var(--border-base); -} .tab-bar-instance { background-color: var(--surface-secondary); diff --git a/src/styles/panels/empty-loading.css b/src/styles/panels/empty-loading.css new file mode 100644 index 00000000..eae70624 --- /dev/null +++ b/src/styles/panels/empty-loading.css @@ -0,0 +1,49 @@ +/* Empty + loading panels */ +.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 { + @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; +} diff --git a/src/styles/panels/modal.css b/src/styles/panels/modal.css new file mode 100644 index 00000000..0bbf9cb6 --- /dev/null +++ b/src/styles/panels/modal.css @@ -0,0 +1,70 @@ +/* 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); +} diff --git a/src/styles/panels/panel-shell.css b/src/styles/panels/panel-shell.css new file mode 100644 index 00000000..81bea902 --- /dev/null +++ b/src/styles/panels/panel-shell.css @@ -0,0 +1,121 @@ +/* Panel component shells */ +.panel { + @apply rounded-lg shadow-sm border overflow-hidden; + 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; +} + +.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; +} + +.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); +} diff --git a/src/styles/panels/session-layout.css b/src/styles/panels/session-layout.css new file mode 100644 index 00000000..cd0ac578 --- /dev/null +++ b/src/styles/panels/session-layout.css @@ -0,0 +1,292 @@ +/* Session view + sidebar */ +.session-view { + @apply flex flex-1 min-h-0 flex-col; + background-color: var(--surface-base); + color: inherit; +} + +.session-list-container { + @apply flex flex-col flex-1 min-h-0 relative; + background-color: var(--surface-secondary); + min-width: 200px; + max-width: 500px; +} + +.session-sidebar { + @apply flex flex-col min-h-0; + background-color: var(--surface-secondary); +} + +.session-sidebar-header { + @apply flex flex-col gap-2 w-full; +} + +.session-sidebar-title { + color: var(--text-primary); +} + +.session-sidebar-shortcuts { + @apply flex flex-col gap-1; +} + +.session-sidebar-new { + @apply w-full; +} + +.session-sidebar-controls { + @apply flex flex-col gap-3; + background-color: var(--surface-secondary); +} + +.session-sidebar-controls > * { + @apply w-full; +} + +.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; +} + +.sidebar-selector-hint { + @apply flex justify-center text-xs w-full; + color: var(--text-muted); +} + +.session-header-hints { + @apply flex-shrink-0; +} + +.session-sidebar-separator { + background-color: var(--border-base); + height: 1px; + width: 100%; +} + +.session-resize-handle { + @apply absolute top-0 right-0 w-1 h-full cursor-col-resize bg-transparent transition-colors; + z-index: 10; +} + +.session-resize-handle:hover { + background-color: var(--accent-primary); +} + +.session-resize-handle::before { + content: ""; + @apply absolute top-0 left-0 w-2 h-full -translate-x-1/2; +} + +.session-list-header { + @apply border-b relative; + border-color: var(--border-base); +} + +.session-list-header h3 { + color: var(--text-primary); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); +} + +.session-list { + @apply flex-1; +} + +.session-list-item { + @apply border-b last:border-b-0; + border-color: var(--border-base); +} + +.session-item-base { + @apply w-full flex flex-col gap-1 px-3 py-2.5 text-left transition-colors outline-none; + font-family: var(--font-family-sans); + font-size: var(--font-size-sm); +} + +.session-item-base:focus-visible { + @apply ring-2 ring-offset-1; + ring-color: var(--accent-primary); + ring-offset-color: var(--surface-secondary); +} + +.session-item-row { + @apply flex items-center gap-2 w-full; +} + +.session-item-header { + @apply justify-between; +} + +.session-item-title-row { + @apply flex items-center gap-2 min-w-0 flex-1; +} + +.session-item-meta { + @apply justify-between items-center; + font-size: var(--font-size-xs); + color: var(--text-secondary); + margin-top: 0.125rem; +} + +.session-item-active .session-item-meta { + color: var(--text-secondary); + opacity: 1; +} + +.session-item-actions { + @apply flex items-center gap-1; +} + +.session-item-active { + background-color: var(--list-item-highlight-bg); + color: var(--text-primary); + font-weight: var(--font-weight-medium); + box-shadow: inset 0 0 0 1px var(--list-item-highlight-border); +} + +.session-item-inactive { + color: var(--text-secondary); +} + +.session-item-inactive:hover { + background-color: var(--surface-hover); + color: var(--text-primary); +} + +.session-item-active .session-item-close:hover { + background-color: var(--surface-hover); + color: var(--text-primary); +} + +.session-item-title { + @apply flex-1 min-w-0; + font-weight: inherit; +} + +.session-item-close { + @apply flex-shrink-0 p-0.5 rounded transition-all; +} + +.session-item-close:focus-visible { + @apply ring-2 ring-offset-1; + ring-color: var(--accent-primary); + ring-offset-color: inherit; +} + +.session-list-footer { + @apply border-t; + border-color: var(--border-base); +} + +.session-new-button { + background-color: var(--surface-base); + color: var(--text-primary); + border: 1px solid var(--border-base); +} + +.session-new-button:hover { + background-color: var(--surface-hover); +} + +.session-new-button:focus-visible { + @apply ring-2 ring-offset-1; + ring-color: var(--accent-primary); + ring-offset-color: var(--surface-secondary); +} + +.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-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-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 .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-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-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; +} + +@media (max-width: 768px) { + .session-list-container { + min-width: 200px; + } + + .session-item-base { + @apply px-2 py-2; + } +} diff --git a/src/styles/panels/tabs.css b/src/styles/panels/tabs.css new file mode 100644 index 00000000..2dd75b7d --- /dev/null +++ b/src/styles/panels/tabs.css @@ -0,0 +1,110 @@ +/* Primary tab strip */ +.tab-bar { + @apply border-b; + border-color: var(--border-base); +} + +.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); +} + +.tab-inactive { + background-color: var(--tab-inactive-bg); + color: var(--tab-inactive-text); +} + +.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-0 group-hover: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 tabs */ +.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); +}