Skip to content
Merged
2 changes: 1 addition & 1 deletion site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const BaseInfraSelectStep: FC<BaseInfraSelectStepProps> = ({
Select your infrastructure foundation.
</TemplateBuilderSubtitle>

<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{bases.map((base) => (
<TemplateCard
key={base.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,13 @@ export const BaseTemplateParametersStep: FC<
<div className="mt-6">
<MemoizedMarkdown
className={cn(
"text-sm font-normal",
"text-xs font-normal",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-17] Dropping the markdown root to text-xs also shrinks fenced code blocks from 14px to 12px, which the description does not mention. (Kite P3, Mafu-san P3, Razor P3)

Kite measured both sides rather than reasoning about them:

With HEAD's class list the fenced block's code renders at 12px/400; with the pre-PR list (text-sm font-normal, no [&_li], no [&_code]) it renders at 14px/400. The SyntaxHighlighter output at Markdown.tsx:78-86 carries no font-size of its own, so it inherits whatever the root sets.

This is shipped content, not an edge case. Razor and Kite both traced it to real bases:

coderd/templatebuilder/bases/aws-linux/README.md and aws-windows/README.md embed a ~40-line json IAM policy, and `bases/docker/README.md` embeds a sh block with the adduser/systemctl commands. The AWS policy is copy-paste material and now renders at 12px monospace inside an overflow-x-auto box in a ~900px column.

The PR description scopes the code change to "Inline <code> inherits body size", so the fenced-block shrink reads as unintended. If 12px monospace is the intent, say so; otherwise pin it with [&_.prismjs]:text-sm. Note [&_pre] will not work: Markdown.tsx:62-73 unwraps the pre when it contains a code. This is not CRF-8's mechanism, which three reviewers independently re-verified as genuinely inert for fenced blocks.

🤖

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note [CRF-37] text-xs also drops paragraph leading from 24px to 16px, a 1.33 ratio on 12px prose. (Hisoka)

The utility changes two things at once, and the README is the one place in this PR with real multi-line prose. 1.33 is tight for body copy; the rest of the class list is explicit about spacing ([&_p]:mb-3, [&_h3]:mt-2 [&_h3]:mb-1), so if the leading is deliberate it would be worth writing it down as leading-normal or similar rather than inheriting whatever the size utility happens to bake.

No change requested. Flagged because it is the same shape as CRF-17 and CRF-18: a size utility here sets three properties, and only one of them was the intent. The pixel baseline will show whether it reads well.

🤖

"[&_h2]:mt-6 [&_h2]:text-base [&_h2]:font-semibold",
"[&_h3]:mt-2 [&_h3]:mb-1 [&_h3]:text-sm [&_h3]:font-semibold",
"[&_p]:mb-3 [&_p]:text-content-secondary",
"[&_li]:text-content-secondary",
"[&_a]:font-normal",
"[&_code]:text-[length:inherit]",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note [CRF-8] [&_code]:text-[length:inherit] also matches fenced-code code elements, with no visual effect today. (Netero)

The probe build confirms it compiles to .[&_code]:text-[length:inherit] code { font-size: inherit }, one specificity step above the inline-code text-sm at site/src/components/Markdown/Markdown.tsx:89, so the inline-code override works as intended. Prism blocks (Markdown.tsx:77-86) render code without a font-size class, so forcing inherit there changes nothing today, but the selector is broader than the stated intent.

No action needed. Flagged so that if a font size is ever added to Prism code blocks, this selector is where it gets overridden.

🤖

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-18] [&_code]:text-[length:inherit] changes one of the three properties text-sm sets, leaving 24px leading on inline code, and the rule belongs in Markdown.tsx where a second consumer already needs it. (Hisoka P3, Zoro P3, Meruem P3)

Hisoka compiled the config and read the declarations:

text-sm is three declarations, not one: font-size, line-height: 1.5rem, and font-weight. The new rule declares exactly one property, font-size: inherit. The code element keeps line-height: 1.5rem. An inline non-replaced element contributes its own line-height to the line box, so a wrapped paragraph whose first line contains inline code gets a 24px line box while its other lines get the 16px that text-xs sets.

The story fixture at BaseTemplateParametersStep.stories.tsx:16 puts inline code inside a two-line bullet, so the snapshot will show it. Unverified in a browser; the CSS derivation is verified.

Zoro found the same override missing at the other compact-markdown consumer, and measured it:

DynamicParameter.tsx:228 renders <MemoizedMarkdown className="text-xs"> and does not have it. I measured that exact configuration: body copy 12px, inline code 14px. Workspace parameter descriptions render oversized inline code today, and this PR's local fix does not reach them.

One change fixes both problems and both call sites: set [&_code]:text-xs here (which carries the matching leading) or fix Markdown.tsx:90 at the source the way Markdown.tsx:55 already handles anchors. Meruem flags the blast radius to weigh before the source fix: markdownClassName sets text-base, so default callsites would move inline code from 14px to 16px. That is a design call, not a mechanical one.

🤖

)}
>
{prerequisites}
Expand Down
8 changes: 4 additions & 4 deletions site/src/pages/TemplateBuilder/ConfigurationField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const SelectField: FC<SelectFieldDefinition> = ({
)}
</Label>
{description && (
<div id={descriptionId} className="text-sm text-content-secondary">
<div id={descriptionId} className="text-xs text-content-secondary">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 [CRF-14] The description slot this PR resizes in four places already exists as one component, FormField, which was already text-xs. (Robin P2, Zoro P3)

FormField.tsx:46-50 renders exactly this block [...] It already wires descriptionId into aria-describedby (FormField.tsx:25-30, :59), and it was already at text-xs before this PR. That is why TextField needed no edit [...] So the change converged the copies on the value FormField already held, not on FormField itself. The copies remain, and they are not decorative: they have already drifted.

Re-raise against CRF-1 with new evidence: the fix moved the resize to the right layer and landed it as four duplicates of a block the codebase owns in one place. ConfigurationField.tsx:138, :188 and :313 are now byte-identical to each other and to FormField's; :279 is the same block plus ml-[44px] font-normal. The measurable cost of the duplication is CRF-15 and CRF-16, both of which are drift between these five copies.

SwitchRow at ConfigurationField.tsx:224-242 is this file's own precedent for extracting a shared sub-component. A FieldDescription sibling, importable by FormField too, collapses five slots to one. I am not asking for a refactor as a condition of this PR, but the next scale or color change to field descriptions is a five-site edit with the same odds of missing one, and this PR is the second lockstep edit in three rounds.

🤖

{description}
</div>
)}
Expand Down Expand Up @@ -185,7 +185,7 @@ const RadioField: FC<RadioFieldDefinition> = ({
)}
</Label>
{description && (
<div id={descriptionId} className="text-sm text-content-secondary">
<div id={descriptionId} className="text-xs text-content-secondary">
{description}
</div>
)}
Expand Down Expand Up @@ -276,7 +276,7 @@ const SwitchField: FC<SwitchFieldDefinition> = ({
{description && (
<div
id={descriptionId}
className="ml-[44px] text-sm font-normal text-content-secondary"
className="ml-[44px] text-xs font-normal text-content-secondary"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-16] Only SwitchField keeps font-normal, so the now-uniform 12px descriptions render at two weights. (Gon P3, Mafuuu P3, Hisoka Nit)

tailwind.config.js:28 bakes fontWeight: "500" into text-xs, so text-xs text-content-secondary at lines 138, 188, and 313 renders at weight 500, while SwitchField at line 279 renders at 400 because it keeps font-normal.

Mafuuu names why this PR is where it becomes visible:

Before the PR the switch description differed in both size and weight, so the weight gap was invisible. Now that sizes match, weight is the only remaining difference and it shows up side by side: in the base-parameters step a string variable renders a FormField description at 500 and a bool variable renders this one at 400 in the same column.

Gon adds that the card descriptions this PR also resized use font-normal (TemplateCard.tsx:74, ModuleCard.tsx:74), so the weight question is already answered elsewhere in the same diff. Pick one weight for description text and apply it to all four slots. This is a different claim from CRF-9, which was about one pairing being correct by source order, not about the four slots disagreeing with each other.

🤖

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit [CRF-35] ml-[44px] is a derived offset with nothing recording the derivation, on a line this PR modifies. (Gon)

44px is Switch's default width (w-9, 36px, Switch.tsx:21) plus the SwitchRow gap (gap-2, 8px, line 232), which aligns the description with the switch label. Nothing states that, so a change to either value silently breaks the alignment.

One line of comment above the div naming the two values it is derived from.

🤖

>
{description}
</div>
Expand Down Expand Up @@ -310,7 +310,7 @@ const SwitchGroupField: FC<SwitchGroupFieldDefinition> = ({
)}
</Label>
{description && (
<div id={descriptionId} className="text-sm text-content-secondary">
<div id={descriptionId} className="text-xs text-content-secondary">
{description}
</div>
)}
Expand Down
6 changes: 3 additions & 3 deletions site/src/pages/TemplateBuilder/ModuleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const ModuleCard: React.FC<ModuleCardProps> = ({
</div>

<div>
<h3 id={nameId} className="text-md font-semibold text-content-primary">
<h3 id={nameId} className="text-sm font-bold text-content-primary">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-21] ModuleCard and TemplateCard are the same component twice, which is why CRF-2 happened, and a third card still carries the old title weight. (Robin P3, Zoro P3, Meruem P3)

ModuleCard.tsx (91 lines) and TemplateCard.tsx (90 lines) differ in three things: role="checkbox" vs role="radio", the selection indicator element (lines 50-61 in each), and detailsUrl optional vs required. Everything else, the container class list, the click and keydown handlers, useId, the avatar row, the heading with the BadgeCheckIcon, the description, the link, is character-for-character identical after this PR.

Robin adds the tell: TemplateCard.stories.tsx and ModuleCard.stories.tsx are also identical apart from the component name and one arg. Meruem found the instance the hand-sync missed:

BaseTemplateCard renders the selected base name as text-sm font-medium, while TemplateCard.tsx:64 and ModuleCard.tsx:65 now use text-sm font-bold. The same base template name therefore renders at weight 700 in the base-infra step and weight 500 in the customizations step.

Re-raise against CRF-2 with new evidence: the fix hand-copied two class strings, which closed the instance and left the mechanism, and there is now a documented third copy at TemplateCustomizationsStep.tsx:184. Only two call sites consume these cards, so a single selectionMode: "radio" | "checkbox" prop covers both. If the cards are meant to diverge visually, say so, because nothing in the code says it today.

🤖

{name}
{official && (
<>
Expand All @@ -71,15 +71,15 @@ export const ModuleCard: React.FC<ModuleCardProps> = ({
</>
)}
</h3>
<p className="text-sm font-normal text-content-secondary">
<p className="text-xs font-normal text-content-secondary">
{description}
</p>

<div>
<Link
href={detailsUrl}
target="_blank"
className="text-sm font-normal"
className="text-xs font-normal"
>
View details
</Link>
Expand Down
2 changes: 1 addition & 1 deletion site/src/pages/TemplateBuilder/ModuleConfiguration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const ModuleConfiguration: React.FC<ModuleConfigurationProps> = ({
</ConfigurationFieldContainer>
</CollapsibleSummary>
) : (
<div className="text-sm text-content-secondary flex items-center gap-2 mt-4">
<div className="text-xs text-content-secondary flex items-center gap-2 mt-4">
<CheckIcon className="size-4" />
No configuration required.
</div>
Expand Down
4 changes: 2 additions & 2 deletions site/src/pages/TemplateBuilder/ModuleSelectStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ export const ModuleSelectStep: FC<ModuleSelectStepProps> = ({
</TabsList>
</Tabs>

<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{visibleModules.length ? (
visibleModules.map((m) => (
<ModuleCard
Expand All @@ -260,7 +260,7 @@ export const ModuleSelectStep: FC<ModuleSelectStepProps> = ({
) : (
<div className="col-span-full my-12 flex flex-col items-center gap-1 text-content-secondary">
<SearchIcon />
<p className="m-0 text-sm font-normal">
<p className="m-0 text-xs font-normal">
{doesBaseTemplateHaveModules
? "No module matched your search"
: "No modules available for this base template"}
Expand Down
2 changes: 1 addition & 1 deletion site/src/pages/TemplateBuilder/ModuleSettingsStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const ModuleSettingsStep: FC<ModuleSettingsStepProps> = ({
/>

{sensitiveVars.length > 0 && (
<div className="flex items-center gap-2 mt-2 p-3 rounded-md text-sm text-content-secondary">
<div className="flex items-center gap-2 mt-2 p-3 rounded-md text-xs text-content-secondary">
<InfoIcon className="size-icon-sm shrink-0 mt-0.5" />
<p>
{sensitiveVars.map((v) => (
Expand Down
6 changes: 3 additions & 3 deletions site/src/pages/TemplateBuilder/TemplateCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
</div>

<div>
<h3 id={nameId} className="text-md font-semibold text-content-primary">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note [CRF-7] The removed text-md was never a real utility. (Netero)

The probe build emitted .text-sm, .text-xs, .font-bold, .font-normal, and both arbitrary variants, but no .text-md. tailwind.config.js:26-31 extends fontSize with 2xs, xs, sm, base, 3xl only, and Tailwind's default scale has no md key. Nine other files still use the dead class, including ModuleCard.tsx:65, DynamicParameter.tsx:400, and four DeploymentSettingsPage charts.

No action needed in this PR. Worth knowing because it changes what this line does: the title was previously unsized and inherited, so text-sm is a new explicit size, not a step down from 16px. The nine remaining uses are a separate cleanup.

🤖

<h3 id={nameId} className="text-sm font-bold text-content-primary">
Comment thread
tracyjohnsonux marked this conversation as resolved.
{name}
{official && (
<>
Expand All @@ -71,14 +71,14 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
)}
</h3>
<div>
<p className="text-sm font-normal text-content-secondary">
<p className="text-xs font-normal text-content-secondary">
Comment thread
tracyjohnsonux marked this conversation as resolved.
{description}
</p>

<Link
href={detailsUrl}
target="_blank"
className="text-sm font-normal"
className="text-xs font-normal"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 [CRF-20] Shrinking the link with a raw text-xs overrides only the font size of Link's lg variant, leaving an 18px icon beside 12px text. (Mafuuu P3)

Link bundles size into a cva variant (site/src/components/Link/Link.tsx:15-16): lg (the default) is text-sm gap-0.5 [&_svg]:size-icon-sm [&_svg]:p-0.5 leading-6, sm is text-xs gap-1 [&_svg]:size-icon-xs [&_svg]:p-px leading-5. The card passes no size, so it gets lg and then hand-writes text-xs font-normal. I ran the repo's cn on those exact inputs; the merged result is relative inline-flex items-center gap-0.5 [&_svg]:size-icon-sm [&_svg]:p-0.5 pl-0.5 text-xs font-normal. text-sm and leading-6 drop out, but the icon sizing stays on the lg scale: size-icon-sm is 1.125rem versus size-icon-xs 0.875rem.

The correct call already exists one step away in the same wizard: TemplateBuilderAvatarData.tsx:32 renders the identical "View details" link with size="sm". So the same link now has two icon geometries in the same flow, which is CRF-4's fix landing on the text but not the component's own scale. Pass size="sm" and drop the text-xs in both cards; ModuleCard.tsx:82 is the sibling instance.

🤖

>
View details
</Link>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ const BaseTemplateCard: FC<{ base: SelectedBaseMeta }> = ({ base }) => {
return (
<div className="w-56 shrink-0 rounded-lg bg-surface-secondary p-4 self-start">
{base.iconUrl && <Avatar src={base.iconUrl} size="lg" variant="icon" />}
<p className="text-sm font-medium text-content-primary">{base.name}</p>
<p className="text-sm font-bold text-content-primary">{base.name}</p>
<p className="text-xs text-content-secondary mt-1">
Preset based on base template
</p>
Expand Down
Loading