Expand dark theme coverage across client UI
This commit is contained in:
@@ -64,17 +64,19 @@ export default function AgentSelector(props: AgentSelectorProps) {
|
||||
itemComponent={(itemProps) => (
|
||||
<Select.Item
|
||||
item={itemProps.item}
|
||||
class="px-3 py-2 cursor-pointer hover:bg-gray-100 rounded outline-none focus:bg-gray-100"
|
||||
class="px-3 py-2 cursor-pointer rounded outline-none transition-colors hover:bg-gray-100 focus:bg-gray-100 dark:hover:bg-gray-800 dark:focus:bg-gray-800"
|
||||
>
|
||||
<div class="flex flex-col">
|
||||
<Select.ItemLabel class="font-medium text-sm text-gray-900 flex items-center gap-2">
|
||||
<Select.ItemLabel class="font-medium text-sm text-gray-900 dark:text-gray-100 flex items-center gap-2">
|
||||
<span>{itemProps.item.rawValue.name}</span>
|
||||
<Show when={itemProps.item.rawValue.mode === "subagent"}>
|
||||
<span class="text-xs font-normal text-blue-600 bg-blue-50 px-1.5 py-0.5 rounded">subagent</span>
|
||||
<span class="text-xs font-normal text-blue-600 dark:text-blue-300 bg-blue-50 dark:bg-blue-900/40 px-1.5 py-0.5 rounded">
|
||||
subagent
|
||||
</span>
|
||||
</Show>
|
||||
</Select.ItemLabel>
|
||||
<Show when={itemProps.item.rawValue.description}>
|
||||
<Select.ItemDescription class="text-xs text-gray-600">
|
||||
<Select.ItemDescription class="text-xs text-gray-600 dark:text-gray-300">
|
||||
{itemProps.item.rawValue.description.length > 50
|
||||
? itemProps.item.rawValue.description.slice(0, 50) + "..."
|
||||
: itemProps.item.rawValue.description}
|
||||
@@ -86,23 +88,25 @@ export default function AgentSelector(props: AgentSelectorProps) {
|
||||
>
|
||||
<Select.Trigger
|
||||
data-agent-selector
|
||||
class="inline-flex items-center justify-between gap-2 px-2 py-1 bg-white border border-gray-300 rounded hover:bg-gray-50 outline-none focus:ring-2 focus:ring-blue-500 text-xs min-w-[100px]"
|
||||
class="inline-flex items-center justify-between gap-2 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700 outline-none focus:ring-2 focus:ring-blue-500 text-xs min-w-[100px] transition-colors"
|
||||
>
|
||||
<Select.Value<Agent>>
|
||||
{(state) => <span class="text-gray-700">Agent: {state.selectedOption()?.name ?? "None"}</span>}
|
||||
{(state) => (
|
||||
<span class="text-gray-700 dark:text-gray-200">Agent: {state.selectedOption()?.name ?? "None"}</span>
|
||||
)}
|
||||
</Select.Value>
|
||||
<Select.Icon>
|
||||
<ChevronDown class="w-3 h-3 text-gray-500" />
|
||||
<ChevronDown class="w-3 h-3 text-gray-500 dark:text-gray-300" />
|
||||
</Select.Icon>
|
||||
</Select.Trigger>
|
||||
|
||||
<Select.Portal>
|
||||
<Select.Content class="bg-white border border-gray-300 rounded-md shadow-lg max-h-80 overflow-auto p-1 z-50">
|
||||
<Select.Listbox />
|
||||
<Select.Content class="bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md shadow-lg max-h-80 overflow-auto p-1 z-50">
|
||||
<Select.Listbox class="bg-white dark:bg-gray-800" />
|
||||
</Select.Content>
|
||||
</Select.Portal>
|
||||
</Select>
|
||||
<span class="text-xs text-gray-400">
|
||||
<span class="text-xs text-gray-400 dark:text-gray-500">
|
||||
<Kbd shortcut="cmd+shift+a" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,9 @@ const InstanceTab: Component<InstanceTabProps> = (props) => {
|
||||
<div class="instance-tab-container 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 text-gray-700 hover:bg-gray-200"
|
||||
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}
|
||||
title={props.instance.folder}
|
||||
@@ -42,7 +44,7 @@ const InstanceTab: Component<InstanceTabProps> = (props) => {
|
||||
{props.instance.folder.split("/").pop() || props.instance.folder}
|
||||
</span>
|
||||
<span
|
||||
class="tab-close opacity-0 group-hover:opacity-100 hover:bg-red-500 hover:text-white rounded p-0.5 transition-opacity ml-auto cursor-pointer"
|
||||
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"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
props.onClose()
|
||||
|
||||
@@ -15,7 +15,7 @@ interface InstanceTabsProps {
|
||||
|
||||
const InstanceTabs: Component<InstanceTabsProps> = (props) => {
|
||||
return (
|
||||
<div class="instance-tabs bg-gray-50 border-b border-gray-200">
|
||||
<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="flex items-center gap-1 overflow-x-auto">
|
||||
<For each={Array.from(props.instances.entries())}>
|
||||
@@ -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 hover:bg-gray-200 transition-colors"
|
||||
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"
|
||||
onClick={props.onNew}
|
||||
title="New instance (Cmd/Ctrl+N)"
|
||||
aria-label="New instance"
|
||||
|
||||
@@ -146,14 +146,14 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="flex-1 flex flex-col overflow-hidden bg-gray-50">
|
||||
<div class="flex-1 flex flex-col overflow-hidden bg-gray-50 dark:bg-gray-950">
|
||||
<div class="flex-1 flex flex-col lg:flex-row gap-4 p-4 overflow-auto">
|
||||
<div class="flex-1 flex flex-col gap-4 min-h-0">
|
||||
<Show
|
||||
when={parentSessions().length > 0}
|
||||
fallback={
|
||||
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 text-center flex-shrink-0">
|
||||
<div class="text-gray-400 mb-2">
|
||||
<div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-6 text-center flex-shrink-0">
|
||||
<div class="text-gray-400 dark:text-gray-500 mb-2">
|
||||
<svg class="w-12 h-12 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
@@ -163,15 +163,15 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-gray-600 font-medium text-sm">No Previous Sessions</p>
|
||||
<p class="text-xs text-gray-500">Create a new session below to get started</p>
|
||||
<p class="text-gray-600 dark:text-gray-200 font-medium text-sm">No Previous Sessions</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">Create a new session below to get started</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden flex-shrink-0">
|
||||
<div class="px-4 py-3 border-b border-gray-200 bg-gray-50">
|
||||
<h2 class="text-base font-semibold text-gray-900">Resume Session</h2>
|
||||
<p class="text-xs text-gray-500 mt-0.5">
|
||||
<div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden flex-shrink-0">
|
||||
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
||||
<h2 class="text-base font-semibold text-gray-900 dark:text-gray-100">Resume Session</h2>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||
{parentSessions().length} {parentSessions().length === 1 ? "session" : "sessions"} available
|
||||
</p>
|
||||
</div>
|
||||
@@ -180,11 +180,10 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
{(session, index) => (
|
||||
<button
|
||||
data-session-index={index()}
|
||||
class="w-full text-left px-4 py-2.5 border-b border-gray-100 hover:bg-blue-50 transition-all group focus:outline-none"
|
||||
class="w-full text-left px-4 py-2.5 border-b border-gray-100 dark:border-gray-800 transition-all group focus:outline-none hover:bg-blue-50 dark:hover:bg-blue-900/30"
|
||||
classList={{
|
||||
"bg-blue-100 ring-2 ring-blue-500 ring-inset":
|
||||
"bg-blue-100 dark:bg-blue-900/50 ring-2 ring-blue-500 dark:ring-blue-400 ring-inset":
|
||||
focusMode() === "sessions" && selectedIndex() === index(),
|
||||
"hover:bg-blue-50": focusMode() !== "sessions" || selectedIndex() !== index(),
|
||||
}}
|
||||
onClick={() => handleSessionSelect(session.id)}
|
||||
onMouseEnter={() => {
|
||||
@@ -196,22 +195,23 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<span
|
||||
class="text-sm font-medium text-gray-900 group-hover:text-blue-700 truncate"
|
||||
class="text-sm font-medium text-gray-900 dark:text-gray-100 group-hover:text-blue-700 dark:group-hover:text-blue-300 truncate"
|
||||
classList={{
|
||||
"text-blue-700": focusMode() === "sessions" && selectedIndex() === index(),
|
||||
"text-blue-700 dark:text-blue-300":
|
||||
focusMode() === "sessions" && selectedIndex() === index(),
|
||||
}}
|
||||
>
|
||||
{session.title || "Untitled Session"}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 text-xs text-gray-500 mt-0.5">
|
||||
<div class="flex items-center gap-3 text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||
<span>{session.agent}</span>
|
||||
<span>•</span>
|
||||
<span>{formatRelativeTime(session.time.updated)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={focusMode() === "sessions" && selectedIndex() === index()}>
|
||||
<kbd class="px-1.5 py-0.5 text-xs font-semibold text-gray-700 bg-white border border-gray-300 rounded flex-shrink-0">
|
||||
<kbd class="px-1.5 py-0.5 text-xs font-semibold text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded flex-shrink-0">
|
||||
↵
|
||||
</kbd>
|
||||
</Show>
|
||||
@@ -223,18 +223,23 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden flex-shrink-0">
|
||||
<div class="px-4 py-3 border-b border-gray-200 bg-gray-50">
|
||||
<h2 class="text-base font-semibold text-gray-900">Start New Session</h2>
|
||||
<p class="text-xs text-gray-500 mt-0.5">Create a fresh conversation with your chosen agent</p>
|
||||
<div class="bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden flex-shrink-0">
|
||||
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
|
||||
<h2 class="text-base font-semibold text-gray-900 dark:text-gray-100">Start New Session</h2>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||
Create a fresh conversation with your chosen agent
|
||||
</p>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<Show when={agentList().length > 0} fallback={<div class="text-sm text-gray-500">Loading agents...</div>}>
|
||||
<Show
|
||||
when={agentList().length > 0}
|
||||
fallback={<div class="text-sm text-gray-500 dark:text-gray-400">Loading agents...</div>}
|
||||
>
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-700 mb-1.5">Agent</label>
|
||||
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1.5">Agent</label>
|
||||
<select
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm bg-white hover:border-gray-400 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 transition-all"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm bg-white dark:bg-gray-800 dark:text-gray-100 hover:border-gray-400 dark:hover:border-gray-500 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 transition-all"
|
||||
value={selectedAgent()}
|
||||
onChange={(e) => setSelectedAgent(e.currentTarget.value)}
|
||||
>
|
||||
@@ -250,7 +255,7 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed transition-all font-medium flex items-center justify-between text-sm relative group"
|
||||
class="w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 dark:hover:bg-blue-500 disabled:bg-gray-300 dark:disabled:bg-gray-600 disabled:cursor-not-allowed transition-all font-medium flex items-center justify-between text-sm relative group focus:outline-none focus:ring-2 focus:ring-blue-500/40"
|
||||
onClick={handleNewSession}
|
||||
disabled={isCreating() || agentList().length === 0}
|
||||
>
|
||||
@@ -276,7 +281,7 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
</svg>
|
||||
<span>Create Session</span>
|
||||
</div>
|
||||
<kbd class="px-1.5 py-0.5 text-xs font-semibold bg-blue-700 border border-blue-500 rounded flex-shrink-0">
|
||||
<kbd class="px-1.5 py-0.5 text-xs font-semibold bg-blue-700 border border-blue-500 rounded flex-shrink-0 dark:bg-blue-600 dark:border-blue-400">
|
||||
Cmd+Enter
|
||||
</kbd>
|
||||
</Show>
|
||||
@@ -294,29 +299,45 @@ const InstanceWelcomeView: Component<InstanceWelcomeViewProps> = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-2 bg-white border-t border-gray-200 flex-shrink-0">
|
||||
<div class="flex items-center justify-center flex-wrap gap-3 text-xs text-gray-500">
|
||||
<div class="px-4 py-2 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 flex-shrink-0">
|
||||
<div class="flex items-center justify-center flex-wrap gap-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded font-mono text-xs">↑</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded font-mono text-xs">↓</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded font-mono text-xs">
|
||||
↑
|
||||
</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded font-mono text-xs">
|
||||
↓
|
||||
</kbd>
|
||||
<span>Navigate</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded font-mono text-xs">PgUp</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded font-mono text-xs">PgDn</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded font-mono text-xs">
|
||||
PgUp
|
||||
</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded font-mono text-xs">
|
||||
PgDn
|
||||
</kbd>
|
||||
<span>Jump</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded font-mono text-xs">Home</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded font-mono text-xs">End</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded font-mono text-xs">
|
||||
Home
|
||||
</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded font-mono text-xs">
|
||||
End
|
||||
</kbd>
|
||||
<span>First/Last</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded font-mono text-xs">Enter</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded font-mono text-xs">
|
||||
Enter
|
||||
</kbd>
|
||||
<span>Resume</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 border border-gray-300 rounded text-xs">Cmd+Enter</kbd>
|
||||
<kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded text-xs">
|
||||
Cmd+Enter
|
||||
</kbd>
|
||||
<span>New Session</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createEffect, createSignal, onMount, onCleanup } from "solid-js"
|
||||
import { renderMarkdown, onLanguagesLoaded } from "../lib/markdown"
|
||||
import { renderMarkdown, onLanguagesLoaded, initMarkdown } from "../lib/markdown"
|
||||
import type { TextPart } from "../types/message"
|
||||
|
||||
interface MarkdownProps {
|
||||
@@ -15,11 +15,16 @@ export function Markdown(props: MarkdownProps) {
|
||||
createEffect(async () => {
|
||||
const part = props.part
|
||||
const text = part.text || ""
|
||||
const dark = Boolean(props.isDark)
|
||||
const themeKey = dark ? "dark" : "light"
|
||||
|
||||
latestRequestedText = text
|
||||
|
||||
if (part.renderCache && part.renderCache.text === text) {
|
||||
setHtml(part.renderCache.html)
|
||||
await initMarkdown(dark)
|
||||
|
||||
const cache = part.renderCache
|
||||
if (cache && cache.text === text && cache.theme === themeKey) {
|
||||
setHtml(cache.html)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28,12 +33,13 @@ export function Markdown(props: MarkdownProps) {
|
||||
|
||||
if (latestRequestedText === text) {
|
||||
setHtml(rendered)
|
||||
part.renderCache = { text, html: rendered }
|
||||
part.renderCache = { text, html: rendered, theme: themeKey }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to render markdown:", error)
|
||||
if (latestRequestedText === text) {
|
||||
setHtml(text)
|
||||
part.renderCache = { text, html: text, theme: themeKey }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -323,11 +323,11 @@ export default function MessageStream(props: MessageStreamProps) {
|
||||
return (
|
||||
<div class="message-stream-container">
|
||||
<div class="connection-status">
|
||||
<div class="flex items-center gap-2 text-sm font-medium text-gray-700">
|
||||
<div class="connection-status-text flex items-center gap-2 text-sm font-medium">
|
||||
<span>{formattedSessionInfo()}</span>
|
||||
</div>
|
||||
<div class="flex-1" />
|
||||
<div class="flex items-center gap-2 text-sm font-medium text-gray-700">
|
||||
<div class="connection-status-text flex items-center gap-2 text-sm font-medium">
|
||||
<span>Command Palette</span>
|
||||
<Kbd shortcut="cmd+shift+p" />
|
||||
</div>
|
||||
|
||||
@@ -78,19 +78,19 @@ export default function ModelSelector(props: ModelSelectorProps) {
|
||||
itemComponent={(itemProps) => (
|
||||
<Combobox.Item
|
||||
item={itemProps.item}
|
||||
class="px-3 py-2 cursor-pointer hover:bg-blue-50 rounded outline-none data-[highlighted]:bg-blue-100 flex items-start gap-2"
|
||||
class="px-3 py-2 cursor-pointer rounded outline-none transition-colors hover:bg-blue-50 dark:hover:bg-blue-900/40 data-[highlighted]:bg-blue-100 dark:data-[highlighted]:bg-blue-900/60 flex items-start gap-2"
|
||||
>
|
||||
<div class="flex flex-col flex-1 min-w-0">
|
||||
<Combobox.ItemLabel class="font-medium text-sm text-gray-900">
|
||||
<Combobox.ItemLabel class="font-medium text-sm text-gray-900 dark:text-gray-100">
|
||||
{itemProps.item.rawValue.name}
|
||||
</Combobox.ItemLabel>
|
||||
<Combobox.ItemDescription class="text-xs text-gray-600">
|
||||
<Combobox.ItemDescription class="text-xs text-gray-600 dark:text-gray-300">
|
||||
{itemProps.item.rawValue.providerName} • {itemProps.item.rawValue.providerId}/
|
||||
{itemProps.item.rawValue.id}
|
||||
</Combobox.ItemDescription>
|
||||
</div>
|
||||
<Combobox.ItemIndicator class="flex-shrink-0 mt-0.5">
|
||||
<svg class="w-4 h-4 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<Combobox.ItemIndicator class="flex-shrink-0 mt-0.5 text-blue-600 dark:text-blue-400">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</Combobox.ItemIndicator>
|
||||
@@ -101,36 +101,38 @@ export default function ModelSelector(props: ModelSelectorProps) {
|
||||
<Combobox.Input class="sr-only" data-model-selector />
|
||||
<Combobox.Trigger
|
||||
ref={triggerRef}
|
||||
class="inline-flex items-center justify-between gap-2 px-2 py-1 bg-white border border-gray-300 rounded hover:bg-gray-50 outline-none focus:ring-2 focus:ring-blue-500 text-xs min-w-[180px]"
|
||||
class="inline-flex items-center justify-between gap-2 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700 outline-none focus:ring-2 focus:ring-blue-500 text-xs min-w-[180px] transition-colors"
|
||||
>
|
||||
<div class="flex flex-col items-start min-w-0">
|
||||
<span class="text-gray-700 font-medium">Model: {currentModelValue()?.name ?? "None"}</span>
|
||||
<span class="text-gray-700 dark:text-gray-200 font-medium">
|
||||
Model: {currentModelValue()?.name ?? "None"}
|
||||
</span>
|
||||
{currentModelValue() && (
|
||||
<span class="text-gray-500 text-[10px]">
|
||||
<span class="text-gray-500 dark:text-gray-400 text-[10px]">
|
||||
{currentModelValue()!.providerId}/{currentModelValue()!.id}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<Combobox.Icon class="flex-shrink-0">
|
||||
<ChevronDown class="w-3 h-3 text-gray-500" />
|
||||
<ChevronDown class="w-3 h-3 text-gray-500 dark:text-gray-300" />
|
||||
</Combobox.Icon>
|
||||
</Combobox.Trigger>
|
||||
</Combobox.Control>
|
||||
|
||||
<Combobox.Portal>
|
||||
<Combobox.Content class="bg-white border border-gray-300 rounded-md shadow-lg overflow-hidden z-50 min-w-[300px]">
|
||||
<div class="p-2 border-b border-gray-200">
|
||||
<Combobox.Content class="bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md shadow-lg overflow-hidden z-50 min-w-[300px]">
|
||||
<div class="p-2 border-b border-gray-200 dark:border-gray-700">
|
||||
<Combobox.Input
|
||||
ref={searchInputRef}
|
||||
class="w-full px-3 py-1.5 text-xs border border-gray-300 rounded outline-none focus:ring-2 focus:ring-blue-500"
|
||||
class="w-full px-3 py-1.5 text-xs border border-gray-300 dark:border-gray-600 rounded outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100"
|
||||
placeholder="Search models..."
|
||||
/>
|
||||
</div>
|
||||
<Combobox.Listbox class="max-h-64 overflow-auto p-1" />
|
||||
<Combobox.Listbox class="max-h-64 overflow-auto p-1 bg-white dark:bg-gray-800" />
|
||||
</Combobox.Content>
|
||||
</Combobox.Portal>
|
||||
</Combobox>
|
||||
<span class="text-xs text-gray-400">
|
||||
<span class="text-xs text-gray-400 dark:text-gray-500">
|
||||
<Kbd shortcut="cmd+shift+m" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -66,28 +66,34 @@ const SessionPicker: Component<SessionPickerProps> = (props) => {
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay class="fixed inset-0 bg-black/50 z-50" />
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||
<Dialog.Content class="bg-white rounded-lg shadow-2xl w-full max-w-lg p-6">
|
||||
<Dialog.Title class="text-xl font-semibold text-gray-900 mb-4">
|
||||
<Dialog.Content class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg shadow-2xl w-full max-w-lg p-6">
|
||||
<Dialog.Title class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
||||
OpenCode • {instance()?.folder.split("/").pop()}
|
||||
</Dialog.Title>
|
||||
|
||||
<div class="space-y-6">
|
||||
<Show
|
||||
when={parentSessions().length > 0}
|
||||
fallback={<div class="text-center py-4 text-gray-500 text-sm">No previous sessions</div>}
|
||||
fallback={
|
||||
<div class="text-center py-4 text-gray-500 dark:text-gray-400 text-sm">No previous sessions</div>
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<h3 class="text-sm font-medium text-gray-700 mb-2">Resume a session ({parentSessions().length}):</h3>
|
||||
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Resume a session ({parentSessions().length}):
|
||||
</h3>
|
||||
<div class="space-y-1 max-h-[400px] overflow-y-auto">
|
||||
<For each={parentSessions()}>
|
||||
{(session) => (
|
||||
<button
|
||||
class="w-full text-left px-3 py-2 rounded hover:bg-gray-100 transition-colors group"
|
||||
class="w-full text-left px-3 py-2 rounded transition-colors group hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||
onClick={() => handleSessionSelect(session.id)}
|
||||
>
|
||||
<div class="flex justify-between items-start">
|
||||
<span class="text-sm text-gray-900 truncate flex-1">{session.title || "Untitled"}</span>
|
||||
<span class="text-xs text-gray-500 ml-2 flex-shrink-0">
|
||||
<span class="text-sm text-gray-900 dark:text-gray-100 truncate flex-1">
|
||||
{session.title || "Untitled"}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400 ml-2 flex-shrink-0">
|
||||
{formatRelativeTime(session.time.updated)}
|
||||
</span>
|
||||
</div>
|
||||
@@ -100,22 +106,22 @@ const SessionPicker: Component<SessionPickerProps> = (props) => {
|
||||
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-300" />
|
||||
<div class="w-full border-t border-gray-300 dark:border-gray-700" />
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="px-2 bg-white text-gray-500">or</span>
|
||||
<span class="px-2 bg-white dark:bg-gray-900 text-gray-500 dark:text-gray-400">or</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="text-sm font-medium text-gray-700 mb-2">Start new session:</h3>
|
||||
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Start new session:</h3>
|
||||
<div class="space-y-3">
|
||||
<Show
|
||||
when={agentList().length > 0}
|
||||
fallback={<div class="text-sm text-gray-500">Loading agents...</div>}
|
||||
fallback={<div class="text-sm text-gray-500 dark:text-gray-400">Loading agents...</div>}
|
||||
>
|
||||
<select
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded text-sm bg-white hover:border-gray-400 transition-colors"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded text-sm bg-white dark:bg-gray-800 dark:text-gray-100 hover:border-gray-400 dark:hover:border-gray-500 transition-colors"
|
||||
value={selectedAgent()}
|
||||
onChange={(e) => setSelectedAgent(e.currentTarget.value)}
|
||||
>
|
||||
@@ -124,7 +130,7 @@ const SessionPicker: Component<SessionPickerProps> = (props) => {
|
||||
</Show>
|
||||
|
||||
<button
|
||||
class="w-full px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed transition-colors"
|
||||
class="w-full px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 dark:hover:bg-blue-500 disabled:bg-gray-300 dark:disabled:bg-gray-600 disabled:cursor-not-allowed transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500/40"
|
||||
onClick={handleNewSession}
|
||||
disabled={isCreating() || agentList().length === 0}
|
||||
>
|
||||
@@ -135,7 +141,10 @@ const SessionPicker: Component<SessionPickerProps> = (props) => {
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-end">
|
||||
<button class="px-4 py-2 text-sm text-gray-700 hover:text-gray-900" onClick={handleCancel}>
|
||||
<button
|
||||
class="px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 transition-colors"
|
||||
onClick={handleCancel}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ const SessionTabs: Component<SessionTabsProps> = (props) => {
|
||||
const totalTabs = () => sessionsList().length + 1
|
||||
|
||||
return (
|
||||
<div class="session-tabs bg-white border-b border-gray-200">
|
||||
<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="flex items-center gap-1 overflow-x-auto">
|
||||
<For each={sessionsList()}>
|
||||
@@ -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 hover:bg-gray-100 transition-colors"
|
||||
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"
|
||||
onClick={props.onNew}
|
||||
title="New parent session (Cmd/Ctrl+T)"
|
||||
aria-label="New parent session"
|
||||
|
||||
Reference in New Issue
Block a user