feat(app): improved session layout
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
[data-slot="hover-card-trigger"] {
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
[data-component="hover-card-content"] {
|
||||
@@ -8,6 +10,7 @@
|
||||
max-width: 320px;
|
||||
border-radius: var(--radius-md);
|
||||
background-color: var(--surface-raised-stronger-non-alpha);
|
||||
pointer-events: auto;
|
||||
|
||||
border: 1px solid color-mix(in oklch, var(--border-base) 50%, transparent);
|
||||
background-clip: padding-box;
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
width: 240px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&[data-size="compact"] {
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="message-nav-item"] {
|
||||
|
||||
@@ -9,9 +9,10 @@ export function MessageNav(
|
||||
current?: UserMessage
|
||||
size: "normal" | "compact"
|
||||
onMessageSelect: (message: UserMessage) => void
|
||||
getLabel?: (message: UserMessage) => string | undefined
|
||||
},
|
||||
) {
|
||||
const [local, others] = splitProps(props, ["messages", "current", "size", "onMessageSelect"])
|
||||
const [local, others] = splitProps(props, ["messages", "current", "size", "onMessageSelect", "getLabel"])
|
||||
|
||||
const content = () => (
|
||||
<ul role="list" data-component="message-nav" data-size={local.size} {...others}>
|
||||
@@ -19,23 +20,36 @@ export function MessageNav(
|
||||
{(message) => {
|
||||
const handleClick = () => local.onMessageSelect(message)
|
||||
|
||||
const handleKeyPress = (event: KeyboardEvent) => {
|
||||
if (event.key !== "Enter" && event.key !== " ") return
|
||||
event.preventDefault()
|
||||
local.onMessageSelect(message)
|
||||
}
|
||||
|
||||
return (
|
||||
<li data-slot="message-nav-item">
|
||||
<Switch>
|
||||
<Match when={local.size === "compact"}>
|
||||
<div data-slot="message-nav-tick-button" data-active={message.id === local.current?.id || undefined}>
|
||||
<div
|
||||
data-slot="message-nav-tick-button"
|
||||
data-active={message.id === local.current?.id || undefined}
|
||||
role="button"
|
||||
tabindex={0}
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyPress}
|
||||
>
|
||||
<div data-slot="message-nav-tick-line" />
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={local.size === "normal"}>
|
||||
<button data-slot="message-nav-message-button" onClick={handleClick}>
|
||||
<button data-slot="message-nav-message-button" onClick={handleClick} onKeyDown={handleKeyPress}>
|
||||
<DiffChanges changes={message.summary?.diffs ?? []} variant="bars" />
|
||||
<div
|
||||
data-slot="message-nav-title-preview"
|
||||
data-active={message.id === local.current?.id || undefined}
|
||||
>
|
||||
<Show when={message.summary?.title} fallback="New message">
|
||||
{message.summary?.title}
|
||||
<Show when={local.getLabel?.(message) ?? message.summary?.title} fallback="New message">
|
||||
{local.getLabel?.(message) ?? message.summary?.title}
|
||||
</Show>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
[data-component="session-message-rail"] {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
[data-slot="session-message-rail-compact"],
|
||||
[data-slot="session-message-rail-full"] {
|
||||
position: absolute;
|
||||
left: 1.5rem;
|
||||
margin-top: 0.625rem;
|
||||
top: 0;
|
||||
bottom: 8rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
[data-slot="session-message-rail-compact"] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
[data-slot="session-message-rail-full"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@container (min-width: 88rem) {
|
||||
[data-slot="session-message-rail-compact"] {
|
||||
display: none;
|
||||
}
|
||||
[data-slot="session-message-rail-full"] {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="session-message-rail"] [data-slot="session-message-rail-full"] {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
[data-component="session-message-rail"][data-wide] [data-slot="session-message-rail-full"] {
|
||||
margin-top: 0.125rem;
|
||||
left: calc(((100% - min(100%, 50rem)) / 2) - 1.5rem);
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
[data-component="session-message-rail"]:not([data-wide]) [data-slot="session-message-rail-full"] {
|
||||
margin-top: 0.625rem;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import { UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import { ComponentProps, Show, splitProps } from "solid-js"
|
||||
import { MessageNav } from "./message-nav"
|
||||
import "./session-message-rail.css"
|
||||
|
||||
export interface SessionMessageRailProps extends ComponentProps<"div"> {
|
||||
messages: UserMessage[]
|
||||
current?: UserMessage
|
||||
wide?: boolean
|
||||
onMessageSelect: (message: UserMessage) => void
|
||||
}
|
||||
|
||||
export function SessionMessageRail(props: SessionMessageRailProps) {
|
||||
const [local, others] = splitProps(props, ["messages", "current", "wide", "onMessageSelect", "class", "classList"])
|
||||
|
||||
return (
|
||||
<Show when={(local.messages?.length ?? 0) > 1}>
|
||||
<div
|
||||
{...others}
|
||||
data-component="session-message-rail"
|
||||
data-wide={local.wide ? "" : undefined}
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
<div data-slot="session-message-rail-compact">
|
||||
<MessageNav
|
||||
messages={local.messages}
|
||||
current={local.current}
|
||||
onMessageSelect={local.onMessageSelect}
|
||||
size="compact"
|
||||
/>
|
||||
</div>
|
||||
<div data-slot="session-message-rail-full">
|
||||
<MessageNav
|
||||
messages={local.messages}
|
||||
current={local.current}
|
||||
onMessageSelect={local.onMessageSelect}
|
||||
size={local.wide ? "normal" : "compact"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user