Files
deepseek-harness/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css
T

229 lines
6.4 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Conversation column skeleton: header (session title + tabs) over the view
area, composer InputBar at the bottom. Column width/squeeze is layout's;
this fills its cell. Figma: Header 39:27730 (83px two-row), tabs 13px with
a 3px active bar. */
.root {
display: flex;
flex-direction: column;
height: 100%;
min-width: 0;
background: var(--dsw-alias-bg-base);
}
.header {
flex: none;
padding: 12px 28px 0 20px;
border-bottom: 1px solid var(--dsw-alias-border-l2);
}
/* Blank hero/settling: keep the header node mounted (stable Session tree for
the wrapActiveBody composer) without taking column space. */
.headerHidden {
display: none;
}
.titleRow {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
min-height: 32px;
}
.sessionTitle {
min-width: 0;
max-width: 100%;
overflow: hidden;
margin: 0;
padding: 4px 8px;
font-size: 14px;
line-height: 20px;
font-weight: 500;
color: var(--dsw-alias-label-primary);
text-overflow: ellipsis;
white-space: nowrap;
}
.headerActions {
display: flex;
flex: none;
align-items: center;
gap: 8px;
}
/* figma Tab_Group 34:11441: 35px strip, gap 36, pad-left 8, tabs bottom-aligned. */
.tabs {
display: flex;
gap: 36px;
margin-top: 4px;
padding-left: 8px;
}
/* figma .Tab 34:11442: 13/16 text (figma wt510, rendered 500), gap 8 to the 3px bar (no bottom rounding). */
.tab {
position: relative;
padding: 0 0 11px;
border: none;
background: transparent;
font-size: 13px;
line-height: 16px;
font-weight: 500;
color: var(--dsw-alias-label-tertiary);
cursor: pointer;
}
.tab::after {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 3px;
background: transparent;
}
/* Selected tab is blue, not ink: brand-primary resolves to neutral black in
this token sheet, so the selected state rides the business blue — the
nearest semantic token that stays blue in both themes. */
.tabActive {
color: var(--dsw-alias-state-business-primary);
}
.tabActive::after {
background: var(--dsw-alias-state-business-primary);
}
.viewArea {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
}
/* Composer context stack (Figma 9:937): standalone dock cards share one
rhythm; the terminal queue strip additionally tucks under the input card. */
.composerStack {
--dsh-composer-stack-gap: 6px;
--dsh-queue-composer-overlap: 5px;
/* InputBar and dock registrants derive their horizontal geometry from the
same card width, outer clearance, and dock inset. */
--dsh-composer-card-max-width: 800px;
--dsh-composer-side-clearance: 32px;
--dsh-composer-dock-inset: 12px;
display: flex;
flex-direction: column;
gap: var(--dsh-composer-stack-gap);
}
/* Common seat for the composer chain (fallback + elected overlay siblings). */
.composerSeat {
display: flex;
flex: none;
flex-direction: column;
/* One cap for every scrolling text region a composer seat can hold: the
InputBar draft (figma Input 75:8208 max 14 lines × 24px line) and the
takeover panels' bodies top out at the same height, so electing a
takeover never grows the footer past the card it replaces. Declared on
the seat because it is the chain's only shared ancestor — fallback and
elected overlay are siblings — and custom properties inherit down to
whichever entry is mounted. */
--dsh-composer-text-max-height: 336px;
}
/* Active phase: header is ordinary column chrome above the scrollport (not
sticky). The scroll body holds the transcript and the sticky composer seat
so wheel over the footer moves the flow. */
.root[data-phase='active'] {
overflow: hidden;
}
.root[data-phase='active'] .header {
flex: none;
}
.scrollBody {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
overflow-y: auto;
}
.root[data-phase='active'] .viewArea {
flex: 1 0 auto;
min-height: auto;
}
.root[data-phase='active'] .composerSeat {
position: sticky;
bottom: 0;
/* Above markdown CodeBlock sticky banners (z-index 6) so the footer never
paints under a sticking code header while scrolling. */
z-index: 7;
/* Input mask (figma 1205:27463): transcript fades out under a FIXED 36px
band at the seat's top (the figma 24% of the resting ~150px composer),
solid below — px stops, not %, so a growing draft only widens the solid
region and the fade band never stretches. The 0px stop is bg-base at
zero alpha (not white, which the figma export hardcodes) so both themes
fade from their own base. */
background: linear-gradient(
180deg,
color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px,
var(--dsw-alias-bg-base) 36px
);
}
/* Hero phase: the composer stack (hero chrome + workspace row + card) is
flex-centered in the column; composer phase docks it at the bottom. Flex,
NOT absolute+transform: a transform would make this box the containing
block for position:fixed descendants (pickers/modals), shrinking them. */
.composerHero {
position: relative; /* .heroGlow positioning context */
align-self: center;
/* figma 75:8208: 12 between hero chrome / workspace row / card. */
gap: 12px;
/* Foot inside the centered box floats the stack a bit above true center. */
padding-bottom: 32px;
width: min(776px, calc(100% - 48px));
z-index: 1;
}
/* Blue backdrop ellipse (figma 313:14109), centered on the input card: the
card's resting center sits ~92px above the stack bottom (32 foot pad +
half of the ~120px two-row card); width tracks the card (glow asset 1051
vs design card 776) so blur scales in userSpace with it. z-index -1 keeps
it behind the in-flow hero content inside this stacking context. */
.heroGlow {
position: absolute;
left: 50%;
bottom: 92px;
z-index: -1;
width: calc(100% * 1051 / 776);
aspect-ratio: 1051 / 468;
transform: translate(-50%, 50%);
pointer-events: none;
}
.heroWorkspaceRow {
display: flex;
align-items: center;
min-width: 0;
padding-left: 8px;
}
/* Hero: the composer sits inside the session scroll body; center there so
the tree seat matches active (sticky footer) without a Root remount. */
.root[data-phase='hero'] .scrollBody {
justify-content: center;
overflow-y: auto;
}
/* Settling (session replaying, hero/docked unknown): keep the composer seat
mounted but invisible so no wrong layout flashes before the phase lands. */
.root[data-phase='settling'] .composerSeat {
visibility: hidden;
}