mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
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:
@@ -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 */}
|
||||
|
||||
Reference in New Issue
Block a user