Skip to content

Commit 74729eb

Browse files
committed
feat: add TemplateCard component
1 parent a68bb60 commit 74729eb

File tree

3 files changed

+149
-15
lines changed

3 files changed

+149
-15
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import type { Interpolation, Theme } from "@emotion/react";
2+
import ArrowForwardOutlined from "@mui/icons-material/ArrowForwardOutlined";
3+
import Button from "@mui/material/Button";
4+
import type { FC, HTMLAttributes } from "react";
5+
import { Link as RouterLink } from "react-router-dom";
6+
import type { Template } from "api/typesGenerated";
7+
import { ExternalAvatar } from "components/Avatar/Avatar";
8+
import { AvatarData } from "components/AvatarData/AvatarData";
9+
import { DeprecatedBadge } from "components/Badges/Badges";
10+
11+
type TemplateCardProps = HTMLAttributes<HTMLDivElement> & {
12+
template: Template;
13+
};
14+
15+
export const TemplateCard: FC<TemplateCardProps> = ({
16+
template,
17+
...divProps
18+
}) => {
19+
const hasIcon = template.icon && template.icon !== "";
20+
21+
return (
22+
<div css={styles.card} {...divProps}>
23+
<div css={styles.header}>
24+
<div >
25+
<AvatarData
26+
title={
27+
template.display_name.length > 0
28+
? template.display_name
29+
: template.name
30+
}
31+
subtitle={template.organization_name}
32+
avatar={
33+
hasIcon && (
34+
<ExternalAvatar variant="square" fitImage src={template.icon} />
35+
)
36+
}
37+
/>
38+
</div>
39+
<div>
40+
{template.active_user_count} {template.active_user_count === 1 ? "user" : "users" }
41+
</div>
42+
</div>
43+
44+
<div>
45+
<span css={styles.description}>
46+
<p>{template.description}</p>
47+
</span>
48+
</div>
49+
50+
<div css={styles.useButtonContainer}>
51+
{template.deprecated ? (
52+
<DeprecatedBadge />
53+
) : (
54+
<Button
55+
component={RouterLink}
56+
css={styles.actionButton}
57+
className="actionButton"
58+
fullWidth
59+
startIcon={<ArrowForwardOutlined />}
60+
title={`Create a workspace using the ${template.display_name} template`}
61+
to={`/templates/${template.name}/workspace`}
62+
>
63+
Create Workspace
64+
</Button>
65+
)}
66+
</div>
67+
</div>
68+
);
69+
};
70+
71+
const styles = {
72+
card: (theme) => ({
73+
width: "320px",
74+
padding: 24,
75+
borderRadius: 6,
76+
border: `1px solid ${theme.palette.divider}`,
77+
textAlign: "left",
78+
color: "inherit",
79+
display: "flex",
80+
flexDirection: "column",
81+
}),
82+
83+
header: {
84+
display: "flex",
85+
alignItems: "center",
86+
justifyContent: "space-between",
87+
marginBottom: 24,
88+
},
89+
90+
icon: {
91+
flexShrink: 0,
92+
paddingTop: 4,
93+
width: 32,
94+
height: 32,
95+
},
96+
97+
tags: {
98+
display: "flex",
99+
flexWrap: "wrap",
100+
gap: 8,
101+
justifyContent: "end",
102+
},
103+
104+
tag: (theme) => ({
105+
borderColor: theme.palette.divider,
106+
textDecoration: "none",
107+
cursor: "pointer",
108+
"&: hover": {
109+
borderColor: theme.palette.primary.main,
110+
},
111+
}),
112+
113+
activeTag: (theme) => ({
114+
borderColor: theme.roles.active.outline,
115+
backgroundColor: theme.roles.active.background,
116+
}),
117+
118+
description: (theme) => ({
119+
fontSize: 13,
120+
color: theme.palette.text.secondary,
121+
lineHeight: "1.6",
122+
display: "block",
123+
}),
124+
125+
useButtonContainer: {
126+
display: "flex",
127+
gap: 12,
128+
flexDirection: "column",
129+
paddingTop: 24,
130+
marginTop: "auto",
131+
alignItems: "center",
132+
},
133+
134+
actionButton: (theme) => ({
135+
transition: "none",
136+
color: theme.palette.text.secondary,
137+
"&:hover": {
138+
borderColor: theme.palette.text.primary,
139+
},
140+
}),
141+
} satisfies Record<string, Interpolation<Theme>>;

site/src/pages/TemplatesPage/TemplatesPage.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export const TemplatesPage: FC = () => {
2222
const error = templatesQuery.error || examplesQuery.error || organizationsQuery.error;
2323
const multiOrgExperimentEnabled = experiments.includes("multi-organization");
2424

25-
console.log({ multiOrgExperimentEnabled })
2625
return (
2726
<>
2827
<Helmet>

site/src/pages/TemplatesPage/TemplatesPageViewV2.tsx

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,12 @@ import {
2121
} from "components/PageHeader/PageHeader";
2222
import { Stack } from "components/Stack/Stack";
2323
// import { createDayString } from "utils/createDayString";
24+
import { TemplateCard } from "modules/templates/TemplateCard/TemplateCard";
2425
import { docs } from "utils/docs";
25-
import {
26-
formatTemplateBuildTime,
27-
formatTemplateActiveDevelopers,
28-
} from "utils/templates";
2926
import { CreateTemplateButton } from "./CreateTemplateButton";
3027
import { EmptyTemplates } from "./EmptyTemplates";
3128

3229
export const Language = {
33-
developerCount: (activeCount: number): string => {
34-
return `${formatTemplateActiveDevelopers(activeCount)} developer${
35-
activeCount !== 1 ? "s" : ""
36-
}`;
37-
},
38-
nameLabel: "Name",
39-
buildTimeLabel: "Build time",
40-
usedByLabel: "Used by",
41-
lastUpdatedLabel: "Last updated",
4230
templateTooltipTitle: "What is template?",
4331
templateTooltipText:
4432
"With templates you can create a common configuration for your workspaces using Terraform.",
@@ -143,7 +131,13 @@ export const TemplatesPageViewV2: FC<TemplatesPageViewProps> = ({
143131
/>
144132
) : (templates &&
145133
templates.map((template) => (
146-
<p key={template.id}>{template.name}</p>
134+
<TemplateCard
135+
css={(theme) => ({
136+
backgroundColor: theme.palette.background.paper,
137+
})}
138+
template={template}
139+
key={template.id}
140+
/>
147141
)))}
148142
</div>
149143
</Stack>

0 commit comments

Comments
 (0)