refactor: restyle tab headers via tokens
This commit is contained in:
@@ -27,24 +27,20 @@ function formatFolderName(path: string, instances: Instance[], currentInstance:
|
|||||||
|
|
||||||
const InstanceTab: Component<InstanceTabProps> = (props) => {
|
const InstanceTab: Component<InstanceTabProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<div class="instance-tab-container group">
|
<div class="group">
|
||||||
<button
|
<button
|
||||||
class={`instance-tab inline-flex items-center gap-2 px-3 py-2 rounded-t-md max-w-[200px] transition-colors ${
|
class={`tab-base ${props.active ? "tab-active" : "tab-inactive"}`}
|
||||||
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"
|
|
||||||
}`}
|
|
||||||
onClick={props.onSelect}
|
onClick={props.onSelect}
|
||||||
title={props.instance.folder}
|
title={props.instance.folder}
|
||||||
role="tab"
|
role="tab"
|
||||||
aria-selected={props.active}
|
aria-selected={props.active}
|
||||||
>
|
>
|
||||||
<FolderOpen class="w-4 h-4 flex-shrink-0" />
|
<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}
|
{props.instance.folder.split("/").pop() || props.instance.folder}
|
||||||
</span>
|
</span>
|
||||||
<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) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
props.onClose()
|
props.onClose()
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ interface InstanceTabsProps {
|
|||||||
|
|
||||||
const InstanceTabs: Component<InstanceTabsProps> = (props) => {
|
const InstanceTabs: Component<InstanceTabsProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<div class="instance-tabs bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
|
<div class="tab-bar tab-bar-instance">
|
||||||
<div class="tabs-container flex items-center justify-between gap-1 px-2 py-1 overflow-x-auto" role="tablist">
|
<div class="tab-container" role="tablist">
|
||||||
<div class="flex items-center gap-1 overflow-x-auto">
|
<div class="flex items-center gap-1 overflow-x-auto">
|
||||||
<For each={Array.from(props.instances.entries())}>
|
<For each={Array.from(props.instances.entries())}>
|
||||||
{([id, instance]) => (
|
{([id, instance]) => (
|
||||||
@@ -29,7 +29,7 @@ const InstanceTabs: Component<InstanceTabsProps> = (props) => {
|
|||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
<button
|
<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}
|
onClick={props.onNew}
|
||||||
title="New instance (Cmd/Ctrl+N)"
|
title="New instance (Cmd/Ctrl+N)"
|
||||||
aria-label="New instance"
|
aria-label="New instance"
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ const SessionTab: Component<SessionTabProps> = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="session-tab-container group">
|
<div class="group">
|
||||||
<button
|
<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
|
props.active
|
||||||
? "bg-white dark:bg-gray-800 border-b-2 border-blue-500 font-medium text-gray-900 dark:text-gray-100"
|
? "session-tab-active"
|
||||||
: "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700"
|
: "session-tab-inactive"
|
||||||
} ${props.special === "info" ? "text-gray-500 dark:text-gray-400" : ""} ${props.isParent && !props.active ? "font-semibold" : ""}`}
|
} ${props.special === "info" ? "session-tab-special" : ""} ${props.isParent && !props.active ? "font-semibold" : ""}`}
|
||||||
onClick={props.onSelect}
|
onClick={props.onSelect}
|
||||||
title={label()}
|
title={label()}
|
||||||
role="tab"
|
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" />}>
|
<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" />
|
<Info class="w-3.5 h-3.5 flex-shrink-0" />
|
||||||
</Show>
|
</Show>
|
||||||
<span class="tab-label truncate">{label()}</span>
|
<span class="tab-label">{label()}</span>
|
||||||
<Show when={!props.special && props.onClose}>
|
<Show when={!props.special && props.onClose}>
|
||||||
<span
|
<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) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
props.onClose?.()
|
props.onClose?.()
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ const SessionTabs: Component<SessionTabsProps> = (props) => {
|
|||||||
const totalTabs = () => sessionsList().length + 1
|
const totalTabs = () => sessionsList().length + 1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="session-tabs bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
|
<div class="tab-bar tab-bar-session">
|
||||||
<div class="tabs-container flex items-center justify-between gap-1 px-2 py-1 overflow-x-auto" role="tablist">
|
<div class="tab-container" role="tablist">
|
||||||
<div class="flex items-center gap-1 overflow-x-auto">
|
<div class="flex items-center gap-1 overflow-x-auto">
|
||||||
<For each={sessionsList()}>
|
<For each={sessionsList()}>
|
||||||
{([id, session]) => (
|
{([id, session]) => (
|
||||||
@@ -39,7 +39,7 @@ const SessionTabs: Component<SessionTabsProps> = (props) => {
|
|||||||
onSelect={() => props.onSelect("info")}
|
onSelect={() => props.onSelect("info")}
|
||||||
/>
|
/>
|
||||||
<button
|
<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}
|
onClick={props.onNew}
|
||||||
title="New parent session (Cmd/Ctrl+T)"
|
title="New parent session (Cmd/Ctrl+T)"
|
||||||
aria-label="New parent session"
|
aria-label="New parent session"
|
||||||
|
|||||||
@@ -153,3 +153,126 @@
|
|||||||
[data-theme="dark"] .attachment-remove:hover {
|
[data-theme="dark"] .attachment-remove:hover {
|
||||||
background-color: rgba(0, 128, 255, 0.2);
|
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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user