← All proposals

Chat Panel

A layout shell for the content of an AI chat drawer or docked side panel.

Net-new componentOpen in Storybook

proposals/ChatPanel/chat-panel.css177 lines · View on GitHub
.pds-chat-panel {
	--chat-panel-inset: var(--pds-spacing-l);

	background-color: var(--pds-color-surface-default);
	color: var(--pds-color-foreground-default);
	display: flex;
	flex-direction: column;
	height: 100%;
	min-height: 0;
	overflow: hidden;
	width: 100%;
}

/* Sizes: the PDS Drawer widths. `m` is the default. */
.pds-chat-panel--m {
	width: 25rem;
}

.pds-chat-panel--l {
	width: 37.5rem;
}

.pds-chat-panel--m,
.pds-chat-panel--l {
	max-width: 100%;
}

/* Title row: always inset so the close button never touches the edge. */
.pds-chat-panel__title-row {
	align-items: center;
	display: flex;
	flex-shrink: 0;
	gap: var(--pds-spacing-s);
	justify-content: flex-end;
	padding-block: var(--pds-spacing-m) var(--pds-spacing-s);
	padding-inline: var(--chat-panel-inset);
}

.pds-chat-panel__title {
	flex: 1;
	min-width: 0;
}

.pds-chat-panel__close {
	flex-shrink: 0;
}

/* Header and footer: pinned. */
.pds-chat-panel__header,
.pds-chat-panel__footer {
	flex-shrink: 0;
}

.pds-chat-panel__header {
	padding-block-end: var(--pds-spacing-s);
}

.pds-chat-panel__footer {
	padding-block: var(--pds-spacing-s) var(--pds-spacing-m);
}

.pds-chat-panel__header--divider {
	border-block-end: var(--pds-border-width-default) solid
		var(--pds-color-border-default-secondary);
}

.pds-chat-panel__footer--divider {
	border-block-start: var(--pds-border-width-default) solid
		var(--pds-color-border-default-secondary);
}

/* Body: holds the scrolling content and, over it, the drop overlay. */
.pds-chat-panel__body {
	display: flex;
	flex: 1;
	flex-direction: column;
	min-height: 0;
	position: relative;
}

/* Content: the only region that scrolls. */
.pds-chat-panel__content {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	padding-block: var(--pds-spacing-s);
}

/* Content fade: the bottom edge fades out into the footer. The mask only needs
   an opaque color. The padding keeps the last line clear at the end. */
.pds-chat-panel__content--fade {
	--chat-panel-fade-height: var(--pds-spacing-2xl);

	-webkit-mask-image: linear-gradient(
		to bottom,
		var(--pds-color-foreground-default)
			calc(100% - var(--chat-panel-fade-height)),
		transparent
	);
	mask-image: linear-gradient(
		to bottom,
		var(--pds-color-foreground-default)
			calc(100% - var(--chat-panel-fade-height)),
		transparent
	);
	padding-block-end: var(--chat-panel-fade-height);
}

/* The end marker for scroll to latest. */
.pds-chat-panel__end {
	height: 0;
}

/* The scroll to latest button floats at the bottom center of the content
   area, over the content and outside the faded element. The wrapper ignores
   the pointer so only the button takes clicks. */
.pds-chat-panel__scroll {
	display: flex;
	inset-block-end: var(--pds-spacing-m);
	inset-inline: 0;
	justify-content: center;
	pointer-events: none;
	position: absolute;
	z-index: 1;
}

.pds-chat-panel__scroll-button.pds-icon-button,
.pds-chat-panel__scroll-button.pds-icon-button:hover:enabled {
	background-color: var(--pds-color-surface-default);
	box-shadow: var(--pds-elevation-raised);
	pointer-events: auto;
}

/* Files dragged over the panel: a faded sheet over the content area with the
   file icons and the label. Pointer events pass through so the drag counter
   stays accurate. */
.pds-chat-panel__drop {
	align-items: center;
	display: flex;
	flex-direction: column;
	gap: var(--pds-spacing-s);
	inset: 0;
	justify-content: center;
	pointer-events: none;
	position: absolute;
	z-index: 1;
}

.pds-chat-panel__drop::before {
	background-color: var(--pds-color-surface-default);
	content: '';
	inset: 0;
	opacity: 0.92;
	position: absolute;
}

.pds-chat-panel__drop-icon,
.pds-chat-panel__drop-label {
	position: relative;
}

/* Inset: `none` removes the inline padding only. */
.pds-chat-panel__header--inset-default,
.pds-chat-panel__content--inset-default,
.pds-chat-panel__footer--inset-default {
	padding-inline: var(--chat-panel-inset);
}

/* Same as the PDS Panel content: l, then xl from the `m` breakpoint. The
   custom media query form doesn't work in this repo, so the port restores
   `@media (--pds-bp-m)`. */
@media (min-width: 768px) {
	.pds-chat-panel {
		--chat-panel-inset: var(--pds-spacing-xl);
	}
}