fix(web): keep onboarding and mobile natal board on one aligned overlay
Put the compact board trigger in the chat header, keep the sheet above the composer on iOS, and align onboarding messages with the intake card on the session column. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1763,8 +1763,24 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
.onboarding-card-heading b { font-size: clamp(22px, 2.6vw, 30px); letter-spacing: -.03em; }
|
||||
.onboarding-card-heading small { max-width: 260px; color: var(--color-ink-secondary); line-height: 1.55; font-size: var(--type-caption); text-wrap: pretty; }
|
||||
.birth-time-intake { gap: var(--space-6); }
|
||||
.conversation.is-onboarding .welcome {
|
||||
box-sizing: border-box;
|
||||
width: min(calc(var(--session-column-width) + (var(--session-column-gutter) * 2)), 100%);
|
||||
margin-inline: auto;
|
||||
}
|
||||
.conversation.is-onboarding.is-empty .welcome {
|
||||
width: min(var(--session-column-width), 100%);
|
||||
}
|
||||
.conversation.is-onboarding .onboarding-card,
|
||||
.conversation.is-onboarding .onboarding-card.birth-time-transition-card {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
margin-inline: 0;
|
||||
}
|
||||
.conversation.is-onboarding-form { align-content: start; padding-bottom: var(--space-8); }
|
||||
.conversation.is-onboarding-form .welcome { padding-top: var(--space-6); padding-bottom: var(--space-8); }
|
||||
.conversation.is-onboarding-form .welcome {
|
||||
padding: var(--space-6) var(--session-column-gutter) var(--space-8);
|
||||
}
|
||||
.conversation.is-onboarding-form .welcome > .onboarding-message:first-child { padding-bottom: var(--space-3); }
|
||||
.conversation.is-onboarding-form .welcome > .onboarding-message:first-child .message-bubble p {
|
||||
max-width: 680px;
|
||||
@@ -1876,6 +1892,8 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
|
||||
.rectification-workspace {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
isolation: isolate;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
@@ -1908,6 +1926,12 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.rectification-workspace.is-compact.is-board-open .rectification-workspace__chat .composer-wrap {
|
||||
z-index: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
.rectification-board {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
@@ -1920,10 +1944,9 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
.rectification-workspace.is-compact .rectification-board-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 20;
|
||||
z-index: 50;
|
||||
display: grid;
|
||||
align-items: end;
|
||||
isolation: isolate;
|
||||
}
|
||||
.rectification-board-scrim {
|
||||
position: absolute;
|
||||
@@ -1937,7 +1960,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 92%;
|
||||
height: 72%;
|
||||
max-height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
@@ -2102,6 +2125,33 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
color: var(--color-ink);
|
||||
font-size: var(--type-caption);
|
||||
}
|
||||
.chat-header-rectification:empty {
|
||||
display: none;
|
||||
}
|
||||
.chat-header-rectification .rectification-board-peek {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: auto;
|
||||
max-width: min(11.5rem, 42vw);
|
||||
min-height: 44px;
|
||||
margin: 0;
|
||||
padding: 0 var(--space-3);
|
||||
gap: var(--space-2);
|
||||
}
|
||||
.chat-header-rectification .rectification-board-peek strong,
|
||||
.chat-header-rectification .rectification-board-peek span {
|
||||
display: inline;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.chat-header-rectification .rectification-board-peek span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.rectification-board-peek {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -3559,6 +3559,7 @@ export default function Home() {
|
||||
<strong>{activeSession?.title || "新对话"}</strong>
|
||||
</div>
|
||||
<div className="chat-header-actions">
|
||||
<div className="chat-header-rectification" data-rectification-header-slot="" />
|
||||
<button className="credit-button" type="button" onClick={() => router.push(membershipHref("credits"))} aria-label={account ? `余额 ${account.credits} 点,会员与充值` : accountError || "读取余额中"}>
|
||||
<Sparkles className="credit-icon" aria-hidden="true" />
|
||||
<span>{account ? account.credits : "—"}</span>
|
||||
@@ -3567,7 +3568,7 @@ export default function Home() {
|
||||
</header>
|
||||
|
||||
{!rectificationSurfaceOpen && (
|
||||
<div ref={conversation} className={`conversation ${!activeSession?.messages.length && !onboardingFormActive ? "is-empty" : ""} ${onboardingFormActive ? "is-onboarding-form" : ""}`}>
|
||||
<div ref={conversation} className={`conversation${!activeSession?.messages.length && !onboardingFormActive ? " is-empty" : ""}${!profileComplete ? " is-onboarding" : ""}${onboardingFormActive ? " is-onboarding-form" : ""}`}>
|
||||
{!activeSession?.messages.length ? (
|
||||
<div className="welcome">
|
||||
{!profileComplete ? (
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { ArrowUp, Square } from "lucide-react";
|
||||
import { useCallback, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { parseAgentReply } from "@/lib/agent-reply";
|
||||
import type { ChatMessage, ChatMessageView } from "@/lib/chat-message-view";
|
||||
import {
|
||||
@@ -262,9 +263,14 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
const [compactBoard, setCompactBoard] = useState(false);
|
||||
const [boardOpen, setBoardOpen] = useState(false);
|
||||
const [boardDiff, setBoardDiff] = useState(() => diffRectificationBoard(null, null));
|
||||
const [headerSlot, setHeaderSlot] = useState<HTMLElement | null>(null);
|
||||
const boardId = useId();
|
||||
const boardTitleId = useId();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setHeaderSlot(document.querySelector("[data-rectification-header-slot]"));
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const query = window.matchMedia(`(max-width: ${RECTIFICATION_BOARD_SPLIT_MIN_PX - 1}px)`);
|
||||
const update = () => {
|
||||
@@ -682,11 +688,21 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
: undefined;
|
||||
const canSend = !busy && !readonly && !regeneratingMessageKey;
|
||||
|
||||
const boardPeek = compactBoard && !boardOpen ? (
|
||||
<RectificationBoardPeek
|
||||
result={candidateResult}
|
||||
expanded={boardOpen}
|
||||
boardId={boardId}
|
||||
onOpen={toggleBoard}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={workspace}
|
||||
className={`rectification-workspace${compactBoard ? " is-compact" : ""}${boardOpen ? " is-board-open" : ""}`}
|
||||
>
|
||||
{headerSlot && boardPeek ? createPortal(boardPeek, headerSlot) : null}
|
||||
<div className="rectification-workspace__chat" inert={compactBoard && boardOpen ? true : undefined}>
|
||||
<section ref={conversation} className="conversation is-rectification" aria-label="生时校正对话" aria-busy={busy || regeneratingMessageKey !== null}>
|
||||
<div className="message-list">
|
||||
@@ -777,14 +793,6 @@ export function RectificationAgenticChat(props: RectificationAgenticChatProps) {
|
||||
</section>
|
||||
|
||||
<div className="composer-wrap">
|
||||
{compactBoard && (
|
||||
<RectificationBoardPeek
|
||||
result={candidateResult}
|
||||
expanded={boardOpen}
|
||||
boardId={boardId}
|
||||
onOpen={toggleBoard}
|
||||
/>
|
||||
)}
|
||||
<form className="composer" onSubmit={submit}>
|
||||
<Textarea
|
||||
ref={composer}
|
||||
|
||||
@@ -271,6 +271,7 @@ export function RectificationBoardPeek({
|
||||
<button
|
||||
className="rectification-board-peek"
|
||||
type="button"
|
||||
aria-label={peek.detail ? `${peek.title},${peek.detail}` : peek.title}
|
||||
aria-expanded={expanded}
|
||||
aria-controls={boardId}
|
||||
onClick={onOpen}
|
||||
|
||||
Reference in New Issue
Block a user