← All proposals

Milestone

Net-new, in two parts, in their own family so "timeline" keeps one meaning (the log).

Net-new componentOpen in Storybook

proposals/Milestone/milestone.css110 lines · View on GitHub
.pds-milestone {
	--milestone-marker-size: var(--pds-spacing-m);
	--milestone-edge: calc(0 * var(--pds-spacing-l));
	--milestone-pad: calc(0 * var(--pds-spacing-l));
}

.pds-milestone--card {
	--milestone-edge: var(--pds-border-width-default);
	--milestone-pad: var(--pds-spacing-l);
}

.pds-milestone__content {
	padding: var(--milestone-pad);
}

.pds-milestone__header {
	display: flex;
	flex-direction: column;
	gap: var(--pds-spacing-2xs);
}

.pds-milestone__title {
	margin: 0;
	position: relative;
}

/* The dot sits on the list's line: it is pulled out to the left by the card's
   padding and the list's inset, and centered on the title's first line. */
.pds-milestone__marker {
	background-color: var(--milestone-dot-fill);
	border: var(--pds-border-width-thicker) solid var(--milestone-dot-edge);
	border-radius: 50%;
	box-shadow:
		0 0 0 var(--pds-border-width-thicker) var(--milestone-dot-ring),
		var(--milestone-dot-shadow);
	box-sizing: border-box;
	height: var(--milestone-marker-size);
	inset-block-start: calc((1lh - var(--milestone-marker-size)) / 2);
	inset-inline-start: calc(
		-1 * var(--milestone-edge) - var(--milestone-pad) - var(--milestone-inset) -
			var(--milestone-marker-size) / 2
	);
	position: absolute;
	width: var(--milestone-marker-size);
}

.pds-milestone {
	--milestone-accent: var(--pds-color-interactive-link-default);
	--milestone-dot-edge: var(--milestone-list-line-color);
	--milestone-dot-fill: var(--pds-color-surface-default);
	--milestone-dot-ring: transparent;
	--milestone-dot-shadow: none;
}

/* Active: the accent fill, a surface-colored edge and a ring past it. */
.pds-milestone--active {
	--milestone-dot-edge: var(--pds-color-surface-default);
	--milestone-dot-fill: var(--milestone-accent);
	--milestone-dot-ring: var(--milestone-accent);
	--milestone-dot-shadow: var(--pds-elevation-raised);
}

.pds-milestone__subtitle {
	color: var(--pds-color-foreground-default-secondary);
}

.pds-milestone__body {
	margin-block-start: var(--pds-spacing-xs);
}

.pds-milestone__body > :first-child {
	margin-block-start: 0;
}

.pds-milestone__body > :last-child {
	margin-block-end: 0;
}

/* Subtitle at the start (MilestoneList `subtitlePosition='start'`, from phone width up):
   the header becomes a grid with a zero-width first column. The subtitle sits
   in it, right-aligned so it overflows toward the line, and baseline-aligned
   with the title. Its end margin carries it past the card's padding, the inset
   and half the dot, plus a gap. */
@media (min-width: 480px) {
	.pds-milestone-list--subtitle-start .pds-milestone__header {
		align-items: baseline;
		column-gap: 0;
		display: grid;
		grid-template-columns: 0 1fr;
	}

	.pds-milestone-list--subtitle-start .pds-milestone__title {
		grid-column: 2;
		grid-row: 1;
	}

	.pds-milestone-list--subtitle-start .pds-milestone__subtitle {
		grid-column: 1;
		grid-row: 1;
		justify-self: end;
		margin-inline-end: calc(
			var(--milestone-edge) + var(--milestone-pad) + var(--milestone-inset) +
				var(--milestone-marker-size) / 2 + var(--pds-spacing-m)
		);
		max-width: var(--milestone-meta-width);
		text-align: end;
		width: max-content;
	}
}