Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/app/e2e/regression/session-summary.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ for (const direction of ["ltr", "rtl"] as const) {
)

const composer = page.locator('[data-component="session-composer-dock"] > div')
const timeline = page.locator('[data-slot="session-timeline-scroll"]')
const summary = page.getByRole("dialog", { name: "Session details", exact: true })
await expect(row).toBeInViewport()
const before = { row: (await row.boundingBox())!, composer: (await composer.boundingBox())! }
Expand All @@ -229,12 +230,13 @@ for (const direction of ["ltr", "rtl"] as const) {
return Math.max(Math.abs(message.x - before.row.x), Math.abs(input.x - before.composer.x))
})
.toBeLessThan(1)
// The capped session column can end before the panel, so the overlay is measured against the whole timeline.
await expect
.poll(async () => {
const message = (await row.boundingBox())!
const view = (await timeline.boundingBox())!
const details = (await summary.boundingBox())!

return Math.min(message.x + message.width, details.x + details.width) - Math.max(message.x, details.x)
return Math.min(view.x + view.width, details.x + details.width) - Math.max(view.x, details.x)
})
.toBeGreaterThan(0)
const text = summary.getByText(branch, { exact: true })
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/composer/dropzone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createAnimatedPresence } from "@/runtime/animated-presence"
export function ComposerDropzone(props: {
active: boolean
input?: { image?: boolean; pdf?: boolean }
identity?: () => unknown
identity?: () => string | undefined
}) {
const language = useLanguage()
const [elements, setElements] = createStore<{ dropzone?: HTMLDivElement }>({})
Expand Down Expand Up @@ -52,7 +52,7 @@ export function ComposerDropzone(props: {
>
<div class="absolute inset-0 bg-v2-background-bg-base/25" />
<div
class="absolute inset-y-0 left-1/2 w-full -translate-x-1/2 md:max-w-200 2xl:max-w-[1000px]"
class="absolute inset-y-0 left-1/2 w-full -translate-x-1/2 md:max-w-session"
style={{
"-webkit-mask-image": "linear-gradient(to right, transparent 0%, black 12%, black 88%, transparent 100%)",
"mask-image": "linear-gradient(to right, transparent 0%, black 12%, black 88%, transparent 100%)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function SessionComposerRegion(props: {
<div
classList={{
"w-full px-3 pointer-events-auto": true,
"md:max-w-[1000px] md:mx-auto": controller.centered(),
"md:max-w-session md:mx-auto": controller.centered(),
}}
>
<Show when={controller.state.websearch.request()}>
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/session/preparing-composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function PreparingComposer(props: { pending: PendingSession }) {

return (
<div data-component="session-composer-dock" class="w-full shrink-0 bg-v2-background-bg-base pb-3">
<div class="mx-auto w-full max-w-[1000px] px-3">
<div class="mx-auto w-full px-3 md:max-w-session">
<ComposerEditor controller={editor} modelControlsVisible={false} />
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/session/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function PreparingSession(props: { sessionID: string; pending: PendingSession })
>
<div data-component="session-preparing" data-workspace-session class="min-h-0 flex-1 overflow-y-auto">
<SessionIdentityHeader sessionID={props.sessionID} />
<div class="mx-auto w-full min-w-0 max-w-[1000px] px-4 pb-5 md:px-5">
<div class="mx-auto w-full min-w-0 px-4 pb-5 md:max-w-session md:px-6">
<SessionUserMessage
sessionID={props.sessionID}
message={props.pending.message}
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/session/timeline/message-timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ function MessageTimelineView(
if (!directory) return
void data.location.vcs.sync({ directory }).catch(() => undefined)
})
const turnPadding = () => "px-4 md:px-5"
const turnPadding = () => "px-4 md:px-6"
const showHeader = createMemo(() => !props.hideHeader && (props.data.showHeader() || workspaceSession()))
const pinned = createMemo(() => props.pinned)
const messageByID = projection.messageByID
Expand Down Expand Up @@ -410,7 +410,7 @@ function MessageTimelineView(
<div
classList={{
"min-w-0 w-full max-w-full": true,
"md:max-w-[1000px] md:mx-auto": props.centered,
"md:max-w-session md:mx-auto": props.centered,
}}
>
<div
Expand Down
5 changes: 5 additions & 0 deletions packages/session-ui/src/components/markdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
margin-bottom: 0;
}

/* Pretty wrapping would move settled words as each token arrives, so the growing block stays greedy until it completes. */
&[data-streaming] > [data-markdown-block]:last-child {
text-wrap-style: auto;
}

/* Headings: Sized by level, distinguished by color and spacing */
h1 {
font-size: 17px;
Expand Down
1 change: 1 addition & 0 deletions packages/session-ui/src/components/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ export function Markdown(
return (
<div
data-component="markdown"
data-streaming={local.streaming ? "" : undefined}
dir="auto"
classList={{
...local.classList,
Expand Down
2 changes: 2 additions & 0 deletions packages/session-ui/src/pierre/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const unsafeCSS = `
color-mix(in lab, var(--diffs-bg) 98%, var(--diffs-mixer)),
color-mix(in lab, var(--diffs-bg) 95%, var(--diffs-mixer))
);
/* The app's code wrapping rules do not reach this shadow tree, and pretty is inherited from the page. */
text-wrap-style: auto;
}

[data-diff],
Expand Down
4 changes: 2 additions & 2 deletions packages/session-ui/src/timeline/session-timeline-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export function createSessionTimelineRowRenderer(input: {
: undefined
}

const padding = () => input.padding?.() ?? "px-4 md:px-5"
const padding = () => input.padding?.() ?? "px-4 md:px-6"

const indexGroupContents = (refs: PartRef[]) => {
const result = new Map<string, Map<string, SessionMessageAssistant["content"][number]>>()
Expand Down Expand Up @@ -470,7 +470,7 @@ export function createSessionTimelineRowRenderer(input: {
data-timeline-spacing={Predicate.isTagged(props.row, "AssistantPart") ? props.row.spacing : undefined}
classList={{
"min-w-0 w-full max-w-full": true,
"md:max-w-[1000px] md:mx-auto": input.centered?.(),
"md:max-w-session md:mx-auto": input.centered?.(),
"pt-2": Predicate.isTagged(props.row, "AssistantPart") && props.row.spacing === "tool",
"pt-4": Predicate.isTagged(props.row, "AssistantPart") && props.row.spacing === "content",
"pt-6": Predicate.isTagged(props.row, "Error"),
Expand Down
14 changes: 14 additions & 0 deletions packages/ui/src/styles/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS.
8. Avoid one-word last lines in all wrapped text. Chromium keeps the line count, so heights do not change.
*/

html,
Expand All @@ -34,6 +35,7 @@ html,
font-feature-settings: var(--font-family-sans--font-feature-settings, normal); /* 5 */
font-variation-settings: var(--font-family-sans--font-variation-settings, normal); /* 6 */
-webkit-tap-highlight-color: transparent; /* 7 */
text-wrap-style: pretty; /* 8 */
}

/*
Expand Down Expand Up @@ -111,6 +113,7 @@ strong {
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
5. Keep code wrapping greedy so wrapped lines break where an editor would.
*/

code,
Expand All @@ -121,6 +124,17 @@ pre {
font-feature-settings: var(--font-family-mono--font-feature-settings, normal); /* 2 */
font-variation-settings: var(--font-family-mono--font-variation-settings, normal); /* 3 */
font-size: 1em; /* 4 */
text-wrap-style: auto; /* 5 */
}

/*
Keep earlier lines still while the user types.
*/

input,
textarea,
[contenteditable] {
text-wrap-style: stable;
}

/*
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/styles/tailwind/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
--container-5xl: 64rem;
--container-6xl: 72rem;
--container-7xl: 80rem;
/* Shared by the session timeline, composer dock, and drop target so their edges stay aligned.
The composer dock's 12px gutter leaves the design's 720px composer. */
--container-session: 744px;

--font-sans: var(--font-family-sans);
--font-sans--font-feature-settings: var(--font-family-sans--font-feature-settings);
Expand Down
Loading