chore: convert emotion styles to tailwind (#19347)

This commit is contained in:
ケイラ
2025-08-18 16:16:21 -06:00
committed by GitHub
parent 42c4792f24
commit e67f0f6f52
17 changed files with 81 additions and 179 deletions
+10 -28
View File
@@ -1,4 +1,5 @@
import type { FC, HTMLAttributes, ReactNode } from "react";
import { cn } from "utils/cn";
export interface EmptyStateProps extends HTMLAttributes<HTMLDivElement> {
/** Text Message to display, placed inside Typography component */
@@ -21,44 +22,25 @@ export const EmptyState: FC<EmptyStateProps> = ({
cta,
image,
isCompact,
className,
...attrs
}) => {
return (
<div
css={[
{
overflow: "hidden",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
minHeight: 360,
padding: "80px 40px",
position: "relative",
},
isCompact && {
minHeight: 180,
padding: "10px 40px",
},
]}
className={cn(
"overflow-hidden flex flex-col justify-center items-center text-center min-h-96 py-20 px-10 relative",
isCompact && "min-h-44 py-2.5",
className,
)}
{...attrs}
>
<h5 css={{ fontSize: 24, fontWeight: 500, margin: 0 }}>{message}</h5>
<h5 className="text-2xl font-medium m-0">{message}</h5>
{description && (
<p
css={(theme) => ({
marginTop: 16,
fontSize: 16,
lineHeight: "140%",
maxWidth: 480,
color: theme.palette.text.secondary,
})}
>
<p className="mt-4 line-height-[140%] max-w-md text-content-secondary">
{description}
</p>
)}
{cta && <div css={{ marginTop: 24 }}>{cta}</div>}
{cta && <div className="mt-6">{cta}</div>}
{image}
</div>
);
@@ -19,7 +19,7 @@ export const FullPageForm: FC<FullPageFormProps> = ({
}) => {
return (
<Margins size="small">
<PageHeader css={{ paddingBottom: 24 }}>
<PageHeader className="pb-6">
<PageHeaderTitle>{title}</PageHeaderTitle>
{detail && <PageHeaderSubtitle>{detail}</PageHeaderSubtitle>}
</PageHeader>
+1 -1
View File
@@ -40,7 +40,7 @@ export const LastSeen: FC<LastSeenProps> = ({ at, className, ...attrs }) => {
return (
<span
data-chromatic="ignore"
css={{ color }}
style={{ color }}
{...attrs}
className={cn(["whitespace-nowrap", className])}
>
+8 -14
View File
@@ -25,11 +25,7 @@ export const Latency: FC<LatencyProps> = ({
if (isLoading) {
return (
<Tooltip title="Loading latency...">
<CircularProgress
size={size}
css={{ marginLeft: "auto" }}
style={{ color }}
/>
<CircularProgress size={size} className="ml-auto" style={{ color }} />
</Tooltip>
);
}
@@ -38,22 +34,20 @@ export const Latency: FC<LatencyProps> = ({
const notAvailableText = "Latency not available";
return (
<Tooltip title={notAvailableText}>
<CircleHelpIcon
className="size-icon-sm"
css={{
marginLeft: "auto",
}}
style={{ color }}
/>
<>
<span css={{ ...visuallyHidden }}>{notAvailableText}</span>
<CircleHelpIcon className="ml-auto size-icon-sm" style={{ color }} />
</>
</Tooltip>
);
}
return (
<p css={{ fontSize: 13, margin: "0 0 0 auto" }} style={{ color }}>
<div className="ml-auto text-sm" style={{ color }}>
<span css={{ ...visuallyHidden }}>Latency: </span>
{latency.toFixed(0)}
<Abbr title="milliseconds">ms</Abbr>
</p>
</div>
);
};
@@ -39,16 +39,7 @@ export const PaginationWidgetBase: FC<PaginationWidgetBaseProps> = ({
);
return (
<div
css={{
justifyContent: "center",
alignItems: "center",
display: "flex",
flexDirection: "row",
padding: "0 20px",
columnGap: "6px",
}}
>
<div className="flex flex-row items-center justify-center px-5 gap-x-1.5">
<PaginationNavButton
disabledMessage="You are already on the first page"
disabled={isPrevDisabled}
+9 -37
View File
@@ -20,24 +20,26 @@ export const Paywall: FC<PaywallProps> = ({
return (
<div css={styles.root}>
<div>
<Stack direction="row" alignItems="center" css={{ marginBottom: 24 }}>
<h5 css={styles.title}>{message}</h5>
<Stack direction="row" alignItems="center" className="mb-6">
<h5 className="font-semibold font-inherit text-xl m-0">{message}</h5>
<PremiumBadge />
</Stack>
{description && <p css={styles.description}>{description}</p>}
{description && (
<p className="font-inherit max-w-md text-sm">{description}</p>
)}
<Link
href={documentationLink}
target="_blank"
rel="noreferrer"
css={{ fontWeight: 600 }}
className="font-semibold"
>
Read the documentation
</Link>
</div>
<div css={styles.separator} />
<div className="w-px h-[220px] bg-highlight-purple/50 ml-2" />
<Stack direction="column" alignItems="left" spacing={3}>
<ul css={styles.featureList}>
<ul className="m-0 px-6 text-sm font-medium">
<li css={styles.feature}>
<FeatureIcon />
High availability & workspace proxies
@@ -55,7 +57,7 @@ export const Paywall: FC<PaywallProps> = ({
Unlimited Git & external auth integrations
</li>
</ul>
<div css={styles.learnButton}>
<div className="px-7">
<Button asChild>
<a
href="https://coder.com/pricing#compare-plans"
@@ -98,36 +100,6 @@ const styles = {
backgroundImage: `linear-gradient(160deg, transparent, ${theme.branding.premium.background})`,
border: `1px solid ${theme.branding.premium.border}`,
}),
title: {
fontWeight: 600,
fontFamily: "inherit",
fontSize: 22,
margin: 0,
},
description: () => ({
fontFamily: "inherit",
maxWidth: 460,
fontSize: 14,
}),
separator: (theme) => ({
width: 1,
height: 220,
backgroundColor: theme.branding.premium.divider,
marginLeft: 8,
}),
learnButton: {
padding: "0 28px",
},
featureList: {
listStyle: "none",
margin: 0,
padding: "0 24px",
fontSize: 14,
fontWeight: 500,
},
featureIcon: (theme) => ({
color: theme.roles.active.fill.outline,
}),
feature: {
display: "flex",
alignItems: "center",
@@ -76,7 +76,7 @@ export const LongButtonText: Story = {
<SelectMenu>
<SelectMenuTrigger>
<SelectMenuButton
css={{ width: 200 }}
className="w-48"
startIcon={<Avatar size="sm" fallback={selectedOpt} />}
>
{selectedOpt}
@@ -107,7 +107,7 @@ export const NoSelectedOption: Story = {
return (
<SelectMenu>
<SelectMenuTrigger>
<SelectMenuButton css={{ width: 200 }}>All users</SelectMenuButton>
<SelectMenuButton className="w-48">All users</SelectMenuButton>
</SelectMenuTrigger>
<SelectMenuContent>
<SelectMenuSearch onChange={action("search")} />
+33 -23
View File
@@ -20,6 +20,7 @@ import {
type ReactElement,
useMemo,
} from "react";
import { cn } from "utils/cn";
const SIDE_PADDING = 16;
@@ -76,19 +77,22 @@ export const SelectMenuSearch: FC<SearchFieldProps> = (props) => {
);
};
export const SelectMenuList: FC<MenuListProps> = (props) => {
export const SelectMenuList: FC<MenuListProps> = ({
children,
className,
...attrs
}) => {
const items = useMemo(() => {
let children = Children.toArray(props.children);
if (!children.every(isValidElement)) {
let items = Children.toArray(children);
if (!items.every(isValidElement)) {
throw new Error("SelectMenuList only accepts MenuItem children");
}
children = moveSelectedElementToFirst(
children as ReactElement<MenuItemProps>[],
);
return children;
}, [props.children]);
items = moveSelectedElementToFirst(items as ReactElement<MenuItemProps>[]);
return items;
}, [children]);
return (
<MenuList css={{ maxHeight: 480 }} {...props}>
<MenuList className={cn("max-h-[480px]", className)} {...attrs}>
{items}
</MenuList>
);
@@ -106,25 +110,31 @@ function moveSelectedElementToFirst(items: ReactElement<MenuItemProps>[]) {
return newItems;
}
export const SelectMenuIcon: FC<HTMLProps<HTMLDivElement>> = (props) => {
return <div css={{ marginRight: 16 }} {...props} />;
export const SelectMenuIcon: FC<HTMLProps<HTMLDivElement>> = ({
children,
className,
...attrs
}) => {
return (
<div className={cn("mr-4", className)} {...attrs}>
{children}
</div>
);
};
export const SelectMenuItem: FC<MenuItemProps> = (props) => {
export const SelectMenuItem: FC<MenuItemProps> = ({
children,
className,
selected,
...attrs
}) => {
return (
<MenuItem
css={{
fontSize: 14,
gap: 0,
lineHeight: 1,
padding: `12px ${SIDE_PADDING}px`,
}}
{...props}
className={cn("text-sm gap-0 leading-none py-3 px-4", className)}
{...attrs}
>
{props.children}
{props.selected && (
<CheckIcon className="size-icon-xs" css={{ marginLeft: "auto" }} />
)}
{children}
{selected && <CheckIcon className="size-icon-xs ml-auto" />}
</MenuItem>
);
};
+1 -1
View File
@@ -106,7 +106,7 @@ export const SidebarNavItem: FC<SidebarNavItemProps> = ({
}
>
<Stack alignItems="center" spacing={1.5} direction="row">
<Icon css={{ width: 16, height: 16 }} />
<Icon className="size-4" />
{children}
</Stack>
</NavLink>
@@ -44,9 +44,8 @@ export const SyntaxHighlighter: FC<SyntaxHighlighterProps> = ({
return (
<div
data-chromatic="ignore"
css={{
padding: "8px 0",
height: "100%",
className="py-2 h-full"
style={{
backgroundColor: theme.monaco.colors["editor.background"],
}}
>
@@ -43,13 +43,7 @@ export const WithImageAndCta: Story = {
<img
src="/featured/templates.webp"
alt=""
css={{
maxWidth: 800,
height: 320,
overflow: "hidden",
objectFit: "cover",
objectPosition: "top",
}}
className="max-w-3xl h-[320px] overflow-hidden object-cover object-top"
/>
),
style: { paddingBottom: 0 },
@@ -11,7 +11,7 @@ type TableEmptyProps = EmptyStateProps;
export const TableEmpty: FC<TableEmptyProps> = (props) => {
return (
<TableRow>
<TableCell colSpan={999} css={{ padding: "0 !important" }}>
<TableCell colSpan={999} className="p-0!">
<EmptyState {...props} />
</TableCell>
</TableRow>
@@ -3,20 +3,7 @@ import type { FC, PropsWithChildren } from "react";
export const TableToolbar: FC<PropsWithChildren> = ({ children }) => {
return (
<div
css={(theme) => ({
fontSize: 13,
marginBottom: "8px",
marginTop: 0,
height: "36px", // The size of a small button
color: theme.palette.text.secondary,
display: "flex",
alignItems: "center",
"& strong": {
color: theme.palette.text.primary,
},
})}
>
<div className="text-sm mb-2 mt-0 h-9 text-content-secondary flex items-center [&_strong]:text-content-primary">
{children}
</div>
);
@@ -42,7 +29,7 @@ export const PaginationStatus: FC<PaginationStatusProps> = (props) => {
if (isLoading) {
return (
<div css={{ height: 24, display: "flex", alignItems: "center" }}>
<div className="h-6 flex items-center">
<Skeleton variant="text" width={160} height={16} />
</div>
);
@@ -167,7 +167,7 @@ export const ProxyMenu: FC<ProxyMenuProps> = ({ proxyContextValue }) => {
<MenuItem
key={proxy.id}
selected={proxy.id === selectedProxy?.id}
css={{ fontSize: 14 }}
className="text-sm"
onClick={() => {
if (!proxy.healthy) {
displayError("Please select a healthy workspace proxy.");
@@ -179,23 +179,12 @@ export const ProxyMenu: FC<ProxyMenuProps> = ({ proxyContextValue }) => {
closeMenu();
}}
>
<div
css={{
display: "flex",
gap: 24,
alignItems: "center",
width: "100%",
}}
>
<div css={{ width: 14, height: 14, lineHeight: 0 }}>
<div className="flex gap-6 items-center w-full">
<div className="leading-[0] size-[14px]">
<img
src={proxy.icon_url}
alt=""
css={{
objectFit: "contain",
width: "100%",
height: "100%",
}}
className="object-fit size-full"
/>
</div>
@@ -125,7 +125,7 @@ export const AnnouncementBannerSettings: FC<
{!isEntitled || banners.length < 1 ? (
<TableCell colSpan={999}>
<EmptyState
css={{ minHeight: 160 }}
className="min-h-[160px]"
message="No announcement banners"
/>
</TableCell>
@@ -161,7 +161,7 @@ export const AnnouncementBannerSettings: FC<
},
]}
>
<div css={{ color: theme.palette.text.secondary }}>
<div className="text-content-secondary">
<p>
Your license does not include Service Banners.{" "}
<Link href="mailto:sales@coder.com">Contact sales</Link> to
@@ -72,7 +72,7 @@ export const EmptyTemplates: FC<EmptyTemplatesProps> = ({
}
cta={
<Stack alignItems="center" spacing={4}>
<div css={styles.featuredExamples}>
<div className="flex flex-wrap justify-center gap-4">
{featuredExamples.map((example) => (
<TemplateExampleCard example={example} key={example.id} />
))}
@@ -91,7 +91,7 @@ export const EmptyTemplates: FC<EmptyTemplatesProps> = ({
return (
<TableEmpty
css={styles.withImage}
className="pb-0"
message="Create a Template"
description="Contact your Coder administrator to create a template. You can share the code below."
cta={<CodeExample secret={false} code="coder templates init" />}
@@ -105,10 +105,6 @@ export const EmptyTemplates: FC<EmptyTemplatesProps> = ({
};
const styles = {
withImage: {
paddingBottom: 0,
},
emptyImage: {
maxWidth: "50%",
height: 320,
@@ -119,11 +115,4 @@ const styles = {
maxWidth: "100%",
},
},
featuredExamples: {
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
gap: 16,
},
} satisfies Record<string, Interpolation<Theme>>;
@@ -103,12 +103,7 @@ export const useSingleSignOnSection = () => {
const SSOEmptyState: FC = () => {
return (
<EmptyState
css={(theme) => ({
minHeight: 0,
padding: "48px 32px",
backgroundColor: theme.palette.background.paper,
borderRadius: 8,
})}
className="rounded-lg border border-solid border-border min-h-0"
message="No SSO Providers"
description="No SSO providers are configured with this Coder deployment."
cta={