Skip to content

Commit cae37d5

Browse files
committed
Refactor template example cards and first create template experience
1 parent e3a351e commit cae37d5

File tree

3 files changed

+119
-106
lines changed

3 files changed

+119
-106
lines changed
Lines changed: 98 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,114 @@
1-
import { type Interpolation, type Theme } from "@emotion/react";
1+
import Button from "@mui/material/Button";
2+
import Link from "@mui/material/Link";
23
import type { TemplateExample } from "api/typesGenerated";
4+
import { Pill } from "components/Pill/Pill";
35
import { type FC } from "react";
4-
import { Link } from "react-router-dom";
6+
import { Link as RouterLink } from "react-router-dom";
57

68
export interface TemplateExampleCardProps {
79
example: TemplateExample;
8-
className?: string;
10+
activeTag?: string;
911
}
1012

1113
export const TemplateExampleCard: FC<TemplateExampleCardProps> = ({
1214
example,
13-
className,
15+
activeTag,
1416
}) => {
1517
return (
16-
<Link
17-
to={`/starter-templates/${example.id}`}
18-
css={styles.template}
19-
className={className}
20-
key={example.id}
18+
<div
19+
css={(theme) => ({
20+
width: "320px",
21+
padding: theme.spacing(3),
22+
borderRadius: 6,
23+
border: `1px solid ${theme.palette.divider}`,
24+
textAlign: "left",
25+
textDecoration: "none",
26+
color: "inherit",
27+
display: "flex",
28+
flexDirection: "column",
29+
})}
2130
>
22-
<div css={styles.templateIcon}>
23-
<img src={example.icon} alt="" />
31+
<div
32+
css={{
33+
flexShrink: 0,
34+
paddingTop: 4,
35+
width: 32,
36+
height: 32,
37+
marginBottom: 16,
38+
}}
39+
>
40+
<img
41+
src={example.icon}
42+
alt=""
43+
css={{ width: "100%", height: "100%", objectFit: "contain" }}
44+
/>
2445
</div>
25-
<div css={styles.templateInfo}>
26-
<span css={styles.templateName}>{example.name}</span>
27-
<span css={styles.templateDescription}>{example.description}</span>
28-
</div>
29-
</Link>
30-
);
31-
};
32-
33-
const styles = {
34-
template: (theme) => ({
35-
border: `1px solid ${theme.palette.divider}`,
36-
borderRadius: theme.shape.borderRadius,
37-
background: theme.palette.background.paper,
38-
textDecoration: "none",
39-
textAlign: "left",
40-
color: "inherit",
41-
display: "flex",
42-
alignItems: "center",
43-
height: "fit-content",
44-
45-
"&:hover": {
46-
backgroundColor: theme.palette.background.paperLight,
47-
},
48-
}),
49-
50-
templateIcon: (theme) => ({
51-
width: theme.spacing(12),
52-
height: theme.spacing(12),
53-
display: "flex",
54-
alignItems: "center",
55-
justifyContent: "center",
56-
flexShrink: 0,
5746

58-
"& img": {
59-
height: theme.spacing(4),
60-
},
61-
}),
47+
<div>
48+
<h4 css={{ fontSize: 14, fontWeight: 600, margin: 0 }}>
49+
{example.name}
50+
</h4>
51+
<span
52+
css={(theme) => ({
53+
fontSize: 13,
54+
color: theme.palette.text.secondary,
55+
lineHeight: "0.5",
56+
})}
57+
>
58+
{example.description}
59+
</span>
60+
<div css={{ marginTop: 16, display: "flex", flexWrap: "wrap", gap: 8 }}>
61+
{example.tags.map((tag) => {
62+
const isActive = activeTag === tag;
6263

63-
templateInfo: (theme) => ({
64-
padding: theme.spacing(2, 2, 2, 0),
65-
display: "flex",
66-
flexDirection: "column",
67-
overflow: "hidden",
68-
}),
69-
70-
templateName: (theme) => ({
71-
fontSize: theme.spacing(2),
72-
textOverflow: "ellipsis",
73-
width: "100%",
74-
overflow: "hidden",
75-
whiteSpace: "nowrap",
76-
}),
64+
return (
65+
<RouterLink key={tag} to={`/starter-templates?tag=${tag}`}>
66+
<Pill
67+
text={tag}
68+
css={(theme) => ({
69+
borderColor: isActive
70+
? theme.palette.primary.main
71+
: theme.palette.divider,
72+
cursor: "pointer",
73+
backgroundColor: isActive
74+
? theme.palette.primary.dark
75+
: undefined,
76+
"&: hover": {
77+
borderColor: theme.palette.primary.main,
78+
},
79+
})}
80+
/>
81+
</RouterLink>
82+
);
83+
})}
84+
</div>
85+
</div>
7786

78-
templateDescription: (theme) => ({
79-
fontSize: theme.spacing(1.75),
80-
color: theme.palette.text.secondary,
81-
textOverflow: "ellipsis",
82-
width: "100%",
83-
overflow: "hidden",
84-
whiteSpace: "nowrap",
85-
}),
86-
} satisfies Record<string, Interpolation<Theme>>;
87+
<div
88+
css={{
89+
display: "flex",
90+
gap: 12,
91+
flexDirection: "column",
92+
paddingTop: 32,
93+
marginTop: "auto",
94+
alignItems: "center",
95+
}}
96+
>
97+
<Button
98+
component={RouterLink}
99+
fullWidth
100+
to={`/templates/new?exampleId=${example.id}`}
101+
>
102+
Use template
103+
</Button>
104+
<Link
105+
component={RouterLink}
106+
css={{ fontSize: 13 }}
107+
to={`/starter-templates/${example.id}`}
108+
>
109+
Read more
110+
</Link>
111+
</div>
112+
</div>
113+
);
114+
};

site/src/pages/StarterTemplatesPage/StarterTemplatesPageView.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,21 @@ export const StarterTemplatesPageView: FC<StarterTemplatesPageViewProps> = ({
7979
</Stack>
8080
)}
8181

82-
<div css={styles.templates}>
82+
<div
83+
css={{
84+
display: "flex",
85+
flexWrap: "wrap",
86+
gap: 32,
87+
height: "max-content",
88+
}}
89+
>
8390
{visibleTemplates &&
8491
visibleTemplates.map((example) => (
85-
<TemplateExampleCard example={example} key={example.id} />
92+
<TemplateExampleCard
93+
example={example}
94+
key={example.id}
95+
activeTag={activeTag}
96+
/>
8697
))}
8798
</div>
8899
</Stack>
@@ -119,12 +130,4 @@ const styles = {
119130
color: theme.palette.text.primary,
120131
fontWeight: 600,
121132
}),
122-
123-
templates: (theme) => ({
124-
flex: "1",
125-
display: "grid",
126-
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
127-
gap: theme.spacing(2),
128-
gridAutoRows: "min-content",
129-
}),
130133
} satisfies Record<string, Interpolation<Theme>>;

site/src/pages/TemplatesPage/EmptyTemplates.tsx

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,17 @@ export const EmptyTemplates: FC<{
4444
if (canCreateTemplates) {
4545
return (
4646
<TableEmpty
47-
message="Create a Template"
47+
message="Create your first template"
4848
description={
4949
<>
5050
Templates are written in Terraform and describe the infrastructure
51-
for workspaces (e.g., docker_container, aws_instance,
52-
kubernetes_pod). Select a starter template below or
51+
for workspaces. You can start using a starter template below or{" "}
5352
<Link
5453
href={docs("/templates/tutorial")}
5554
target="_blank"
5655
rel="noreferrer"
5756
>
58-
create your own
57+
creating your own
5958
</Link>
6059
.
6160
</>
@@ -64,19 +63,15 @@ export const EmptyTemplates: FC<{
6463
<Stack alignItems="center" spacing={4}>
6564
<div css={styles.featuredExamples}>
6665
{featuredExamples.map((example) => (
67-
<TemplateExampleCard
68-
example={example}
69-
key={example.id}
70-
css={styles.template}
71-
/>
66+
<TemplateExampleCard example={example} key={example.id} />
7267
))}
7368
</div>
7469

7570
<Button
7671
size="small"
7772
component={RouterLink}
7873
to="/starter-templates"
79-
css={styles.viewAllButton}
74+
css={{ borderRadius: 9999 }}
8075
>
8176
View all starter templates
8277
</Button>
@@ -118,22 +113,9 @@ const styles = {
118113
}),
119114

120115
featuredExamples: (theme) => ({
121-
maxWidth: theme.spacing(100),
122-
display: "grid",
123-
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
116+
display: "flex",
117+
flexWrap: "wrap",
118+
justifyContent: "center",
124119
gap: theme.spacing(2),
125-
gridAutoRows: "min-content",
126120
}),
127-
128-
template: (theme) => ({
129-
backgroundColor: theme.palette.background.paperLight,
130-
131-
"&:hover": {
132-
backgroundColor: theme.palette.divider,
133-
},
134-
}),
135-
136-
viewAllButton: {
137-
borderRadius: 9999,
138-
},
139121
} satisfies Record<string, Interpolation<Theme>>;

0 commit comments

Comments
 (0)