refactor: restyle tab headers via tokens

This commit is contained in:
Shantur Rathore
2025-10-28 19:47:05 +00:00
parent a355d9c4b8
commit a541f79910
5 changed files with 140 additions and 21 deletions

View File

@@ -27,24 +27,20 @@ function formatFolderName(path: string, instances: Instance[], currentInstance:
const InstanceTab: Component<InstanceTabProps> = (props) => {
return (
<div class="instance-tab-container group">
<div class="group">
<button
class={`instance-tab inline-flex items-center gap-2 px-3 py-2 rounded-t-md max-w-[200px] transition-colors ${
props.active
? "bg-blue-500 text-white"
: "bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700"
}`}
class={`tab-base ${props.active ? "tab-active" : "tab-inactive"}`}
onClick={props.onSelect}
title={props.instance.folder}
role="tab"
aria-selected={props.active}
>
<FolderOpen class="w-4 h-4 flex-shrink-0" />
<span class="tab-label truncate text-sm">
<span class="tab-label">
{props.instance.folder.split("/").pop() || props.instance.folder}
</span>
<span
class="tab-close opacity-0 group-hover:opacity-100 hover:bg-red-500 dark:hover:bg-red-600 hover:text-white rounded p-0.5 transition-opacity ml-auto cursor-pointer"
class="tab-close ml-auto"
onClick={(e) => {
e.stopPropagation()
props.onClose()

View File

@@ -15,8 +15,8 @@ interface InstanceTabsProps {
const InstanceTabs: Component<InstanceTabsProps> = (props) => {
return (
<div class="instance-tabs bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
<div class="tabs-container flex items-center justify-between gap-1 px-2 py-1 overflow-x-auto" role="tablist">
<div class="tab-bar tab-bar-instance">
<div class="tab-container" role="tablist">
<div class="flex items-center gap-1 overflow-x-auto">
<For each={Array.from(props.instances.entries())}>
{([id, instance]) => (
@@ -29,7 +29,7 @@ const InstanceTabs: Component<InstanceTabsProps> = (props) => {
)}
</For>
<button
class="new-tab-button inline-flex items-center justify-center w-8 h-8 rounded-md text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-800 transition-colors"
class="new-tab-button"
onClick={props.onNew}
title="New instance (Cmd/Ctrl+N)"
aria-label="New instance"

View File

@@ -18,13 +18,13 @@ const SessionTab: Component<SessionTabProps> = (props) => {
}
return (
<div class="session-tab-container group">
<div class="group">
<button
class={`session-tab inline-flex items-center gap-2 px-3 py-1.5 rounded-t-md max-w-[150px] transition-colors text-sm ${
class={`session-tab-base ${
props.active
? "bg-white dark:bg-gray-800 border-b-2 border-blue-500 font-medium text-gray-900 dark:text-gray-100"
: "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700"
} ${props.special === "info" ? "text-gray-500 dark:text-gray-400" : ""} ${props.isParent && !props.active ? "font-semibold" : ""}`}
? "session-tab-active"
: "session-tab-inactive"
} ${props.special === "info" ? "session-tab-special" : ""} ${props.isParent && !props.active ? "font-semibold" : ""}`}
onClick={props.onSelect}
title={label()}
role="tab"
@@ -33,10 +33,10 @@ const SessionTab: Component<SessionTabProps> = (props) => {
<Show when={props.special === "info"} fallback={<MessageSquare class="w-3.5 h-3.5 flex-shrink-0" />}>
<Info class="w-3.5 h-3.5 flex-shrink-0" />
</Show>
<span class="tab-label truncate">{label()}</span>
<span class="tab-label">{label()}</span>
<Show when={!props.special && props.onClose}>
<span
class="tab-close opacity-0 group-hover:opacity-100 hover:bg-red-500 hover:text-white rounded p-0.5 transition-opacity cursor-pointer"
class="tab-close"
onClick={(e) => {
e.stopPropagation()
props.onClose?.()

View File

@@ -19,8 +19,8 @@ const SessionTabs: Component<SessionTabsProps> = (props) => {
const totalTabs = () => sessionsList().length + 1
return (
<div class="session-tabs bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
<div class="tabs-container flex items-center justify-between gap-1 px-2 py-1 overflow-x-auto" role="tablist">
<div class="tab-bar tab-bar-session">
<div class="tab-container" role="tablist">
<div class="flex items-center gap-1 overflow-x-auto">
<For each={sessionsList()}>
{([id, session]) => (
@@ -39,7 +39,7 @@ const SessionTabs: Component<SessionTabsProps> = (props) => {
onSelect={() => props.onSelect("info")}
/>
<button
class="new-tab-button inline-flex items-center justify-center w-8 h-8 rounded-md text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
class="new-tab-button"
onClick={props.onNew}
title="New parent session (Cmd/Ctrl+T)"
aria-label="New parent session"

View File

@@ -152,4 +152,127 @@
[data-theme="dark"] .attachment-remove:hover {
background-color: rgba(0, 128, 255, 0.2);
}
/* Tab component utilities */
.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);
}
[data-theme="dark"] .tab-bar-session {
background-color: var(--surface-secondary);
}
.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(--accent-primary);
color: var(--text-inverted);
}
.tab-inactive {
background-color: var(--surface-secondary);
color: var(--text-secondary);
}
.tab-inactive:hover {
background-color: var(--surface-hover);
}
[data-theme="dark"] .tab-inactive {
background-color: var(--surface-muted);
}
[data-theme="dark"] .tab-inactive:hover {
background-color: var(--surface-hover);
}
.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(--surface-secondary);
color: var(--text-muted);
}
.new-tab-button:hover {
background-color: var(--surface-hover);
}
.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(--surface-base);
border-bottom-color: var(--accent-primary);
color: var(--text-primary);
font-weight: var(--font-weight-medium);
}
[data-theme="dark"] .session-tab-active {
background-color: var(--surface-muted);
}
.session-tab-inactive {
color: var(--text-muted);
}
.session-tab-inactive:hover {
background-color: var(--surface-hover);
}
.session-tab-special {
color: var(--text-muted);
}