feat(site): limit dropdown module config fields to 50% width (#26682)

closes DEVEX-532

## other changes

just cleaning up typographic styles a bit to match Figma better

- create `TemplateBuilderTitle`/`TemplateBuilderSubtitle` components for
h2+p elements at the top of steps
- left-align switch's description with its label
This commit is contained in:
Andrew Aquino
2026-06-25 10:49:46 -07:00
committed by GitHub
parent 72093ae0af
commit 973056dcf6
8 changed files with 73 additions and 25 deletions
@@ -4,6 +4,10 @@ import { templateBuilderBases } from "#/api/queries/templateBuilder";
import type { TemplateBuilderBase } from "#/api/typesGenerated";
import { ErrorAlert } from "#/components/Alert/ErrorAlert";
import { Loader } from "#/components/Loader/Loader";
import {
TemplateBuilderSubtitle,
TemplateBuilderTitle,
} from "#/pages/TemplateBuilder/TemplateBuilderHeader";
import { TemplateCard } from "./TemplateCard";
import type { SelectedBaseMeta } from "./wizardState";
@@ -46,10 +50,11 @@ export const BaseInfraSelectStep: FC<BaseInfraSelectStepProps> = ({
return (
<div role="radiogroup" aria-label="Base infrastructure templates">
<h2 className="text-lg font-semibold mb-1">Pick a base template</h2>
<p className="text-sm text-content-secondary mb-4">
<TemplateBuilderTitle>Pick a base template</TemplateBuilderTitle>
<TemplateBuilderSubtitle>
Select your infrastructure foundation.
</p>
</TemplateBuilderSubtitle>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{bases.map((base) => (
<TemplateCard
@@ -1,4 +1,4 @@
import type { FC, ReactNode } from "react";
import type { FC, PropsWithChildren, ReactNode } from "react";
import { FormField } from "#/components/FormField/FormField";
import { Label } from "#/components/Label/Label";
import { RadioGroup, RadioGroupItem } from "#/components/RadioGroup/RadioGroup";
@@ -118,7 +118,8 @@ const SelectField: FC<SelectFieldDefinition> = ({
}) => {
const descriptionId = `${id}-description`;
return (
<div className="flex flex-col gap-2">
// All fields span 2 columns, except for dropdowns which can only be 1 column (50% width)
<div className="!col-end-1 flex flex-col gap-2">
<Label htmlFor={id}>
{label}
{required && (
@@ -231,9 +232,7 @@ const SwitchRow: FC<{
onCheckedChange={onCheckedChange}
aria-describedby={describedBy}
/>
<Label htmlFor={id} className="font-normal">
{label}
</Label>
<Label htmlFor={id}>{label}</Label>
</div>
);
@@ -270,7 +269,10 @@ const SwitchField: FC<SwitchFieldDefinition> = ({
describedBy={description ? descriptionId : undefined}
/>
{description && (
<div id={descriptionId} className="text-sm text-content-secondary">
<div
id={descriptionId}
className="ml-[44px] text-sm font-normal text-content-secondary"
>
{description}
</div>
)}
@@ -323,3 +325,13 @@ const SwitchGroupField: FC<SwitchGroupFieldDefinition> = ({
</div>
);
};
export const ConfigurationFieldContainer: FC<PropsWithChildren> = ({
children,
}) => {
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start *:col-start-1 *:col-span-full">
{children}
</div>
);
};
@@ -4,6 +4,7 @@ import { CollapsibleSummary } from "#/components/CollapsibleSummary/CollapsibleS
import { Link } from "#/components/Link/Link";
import {
ConfigurationField,
ConfigurationFieldContainer,
type ConfigurationFieldDefinition,
} from "./ConfigurationField";
@@ -73,18 +74,20 @@ export const ModuleConfiguration: React.FC<ModuleConfigurationProps> = ({
</header>
{fields && fields.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start">
<ConfigurationFieldContainer>
{fields.map((field) => (
<ConfigurationField key={field.id} field={field} />
))}
</div>
</ConfigurationFieldContainer>
)}
{optionalFields && optionalFields.length > 0 && (
<CollapsibleSummary label="Advanced settings" className="mt-4">
{optionalFields.map((f) => (
<ConfigurationField key={f.id} field={f} />
))}
<ConfigurationFieldContainer>
{optionalFields.map((f) => (
<ConfigurationField key={f.id} field={f} />
))}
</ConfigurationFieldContainer>
</CollapsibleSummary>
)}
</section>
@@ -8,6 +8,10 @@ import type {
import { Alert, AlertDescription, AlertTitle } from "#/components/Alert/Alert";
import { ErrorAlert } from "#/components/Alert/ErrorAlert";
import { Loader } from "#/components/Loader/Loader";
import {
TemplateBuilderSubtitle,
TemplateBuilderTitle,
} from "#/pages/TemplateBuilder/TemplateBuilderHeader";
import { ModuleCard } from "./ModuleCard";
import {
moduleHasConfigurableVars,
@@ -133,10 +137,10 @@ export const ModuleSelectStep: FC<ModuleSelectStepProps> = ({
return (
<div>
<h2 className="text-lg font-semibold mb-1">Select modules</h2>
<p className="text-sm text-content-secondary mb-4">
<TemplateBuilderTitle>Select modules</TemplateBuilderTitle>
<TemplateBuilderSubtitle>
Add functionality to your template.
</p>
</TemplateBuilderSubtitle>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{modules.map((m) => (
@@ -7,6 +7,10 @@ import type {
TemplateBuilderModulesResponse,
TemplateBuilderModuleVariable,
} from "#/api/typesGenerated";
import {
TemplateBuilderSubtitle,
TemplateBuilderTitle,
} from "#/pages/TemplateBuilder/TemplateBuilderHeader";
import type { ConfigurationFieldDefinition } from "./ConfigurationField";
import { ModuleConfiguration } from "./ModuleConfiguration";
@@ -111,10 +115,10 @@ export const ModuleSettingsStep: FC<ModuleSettingsStepProps> = ({
return (
<div className="border border-border border-solid p-6 rounded-lg">
<h2 className="text-lg font-semibold mb-1">Configure modules</h2>
<p className="text-sm text-content-secondary mb-4">
<TemplateBuilderTitle>Configure modules</TemplateBuilderTitle>
<TemplateBuilderSubtitle>
Set values for module variables.
</p>
</TemplateBuilderSubtitle>
<div className="flex flex-col gap-6">
{selectedModules.map((mod) => {
@@ -0,0 +1,15 @@
import type { FC, PropsWithChildren } from "react";
export const TemplateBuilderTitle: FC<PropsWithChildren> = ({ children }) => {
return <h2 className="text-xl font-semibold mb-1">{children}</h2>;
};
export const TemplateBuilderSubtitle: FC<PropsWithChildren> = ({
children,
}) => {
return (
<p className="mt-0 text-sm font-normal text-content-secondary mb-4">
{children}
</p>
);
};
@@ -2,6 +2,7 @@ import type { PropsWithChildren } from "react";
import { Link } from "#/components/Link/Link";
import {
ConfigurationField,
ConfigurationFieldContainer,
type ConfigurationFieldDefinition,
} from "./ConfigurationField";
@@ -54,11 +55,11 @@ export const TemplateConfiguration: React.FC<TemplateConfigurationProps> = ({
</header>
{fields && fields.length > 0 && (
<div className="space-y-6">
<ConfigurationFieldContainer>
{fields.map((field) => (
<ConfigurationField key={field.id} field={field} />
))}
</div>
</ConfigurationFieldContainer>
)}
{children}
</section>
@@ -7,6 +7,10 @@ import { Input } from "#/components/Input/Input";
import { Label } from "#/components/Label/Label";
import { OrganizationAutocomplete } from "#/components/OrganizationAutocomplete/OrganizationAutocomplete";
import { Textarea } from "#/components/Textarea/Textarea";
import {
TemplateBuilderSubtitle,
TemplateBuilderTitle,
} from "#/pages/TemplateBuilder/TemplateBuilderHeader";
import type {
SelectedBaseMeta,
TemplateBuilderWizardState,
@@ -48,10 +52,10 @@ export const TemplateCustomizationsStep: FC<
return (
<div className="border border-border border-solid p-6 rounded-lg">
<h2 className="text-lg font-semibold mb-1">Customizations</h2>
<p className="text-sm text-content-secondary mb-6">
<TemplateBuilderTitle>Customizations</TemplateBuilderTitle>
<TemplateBuilderSubtitle>
Add additional configurations.
</p>
</TemplateBuilderSubtitle>
<div className="flex gap-8">
{/* Base template card */}