refactor(site): migrate more styles from emotion to tailwind (#24914)

This commit is contained in:
Kayla はな
2026-05-07 11:09:25 -06:00
committed by GitHub
parent 89034f6422
commit 9fd2cc78fe
18 changed files with 210 additions and 235 deletions
+1 -9
View File
@@ -1,4 +1,3 @@
import { type CSSObject, useTheme } from "@emotion/react";
import type { FC, ReactNode } from "react"; import type { FC, ReactNode } from "react";
import { Avatar } from "#/components/Avatar/Avatar"; import { Avatar } from "#/components/Avatar/Avatar";
import { cn } from "#/utils/cn"; import { cn } from "#/utils/cn";
@@ -16,8 +15,6 @@ export const AvatarCard: FC<AvatarCardProps> = ({
subtitle, subtitle,
maxWidth = "none", maxWidth = "none",
}) => { }) => {
const theme = useTheme();
return ( return (
<div <div
className={cn( className={cn(
@@ -44,12 +41,7 @@ export const AvatarCard: FC<AvatarCardProps> = ({
</h3> </h3>
{subtitle && ( {subtitle && (
<div <div className="text-sm leading-relaxed text-content-secondary">
css={[
theme.typography.body2 as CSSObject,
{ color: theme.palette.text.secondary },
]}
>
{subtitle} {subtitle}
</div> </div>
)} )}
@@ -1,5 +1,5 @@
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
import { type FC, type FormEvent, useId, useState } from "react"; import { useId, useState } from "react";
import { Alert } from "#/components/Alert/Alert"; import { Alert } from "#/components/Alert/Alert";
import { ConfirmDialog } from "../ConfirmDialog/ConfirmDialog"; import { ConfirmDialog } from "../ConfirmDialog/ConfirmDialog";
@@ -17,7 +17,7 @@ interface DeleteDialogProps {
confirmText?: string; confirmText?: string;
} }
export const DeleteDialog: FC<DeleteDialogProps> = ({ export const DeleteDialog: React.FC<DeleteDialogProps> = ({
isOpen, isOpen,
onCancel, onCancel,
onConfirm, onConfirm,
@@ -37,7 +37,7 @@ export const DeleteDialog: FC<DeleteDialogProps> = ({
const [isFocused, setIsFocused] = useState(false); const [isFocused, setIsFocused] = useState(false);
const deletionConfirmed = name === userConfirmationText; const deletionConfirmed = name === userConfirmationText;
const onSubmit = (event: FormEvent) => { const onSubmit = (event: React.SubmitEvent) => {
event.preventDefault(); event.preventDefault();
if (deletionConfirmed) { if (deletionConfirmed) {
onConfirm(); onConfirm();
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import { import {
cloneElement, cloneElement,
type FC, type FC,
@@ -51,10 +50,9 @@ export const TopbarData: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
export const TopbarDivider: FC< export const TopbarDivider: FC<
Omit<HTMLAttributes<HTMLSpanElement>, "children"> Omit<HTMLAttributes<HTMLSpanElement>, "children">
> = (props) => { > = ({ className, ...props }) => {
const theme = useTheme();
return ( return (
<span {...props} css={{ color: theme.palette.divider }}> <span {...props} className={cn("text-border", className)}>
/ /
</span> </span>
); );
@@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
import LinearProgress from "./LinearProgress"; import LinearProgress from "./LinearProgress";
const meta: Meta<typeof LinearProgress> = { const meta: Meta<typeof LinearProgress> = {
title: "Components/LinearProgress", title: "components/LinearProgress",
component: LinearProgress, component: LinearProgress,
args: { args: {
variant: "determinate", variant: "determinate",
@@ -56,7 +56,7 @@ export const InlineMarkdown: FC<InlineMarkdownProps> = (props) => {
code: ({ node, className, children, style, ...props }) => ( code: ({ node, className, children, style, ...props }) => (
<code <code
className="rounded-sm bg-border px-1 py-px text-[14px] text-content-primary" className="rounded-sm bg-border px-1 py-px text-sm text-content-primary"
{...props} {...props}
> >
{children} {children}
+1 -1
View File
@@ -85,7 +85,7 @@ export const Markdown: FC<MarkdownProps> = (props) => {
</SyntaxHighlighter> </SyntaxHighlighter>
) : ( ) : (
<code <code
className="rounded-sm bg-border px-1 py-px text-[14px] text-content-primary" className="rounded-sm bg-border px-1 py-px text-sm text-content-primary"
{...restProps} {...restProps}
> >
{children} {children}
+9 -24
View File
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import { Building2Icon, UserIcon } from "lucide-react"; import { Building2Icon, UserIcon } from "lucide-react";
import type { FC } from "react"; import type { FC } from "react";
import type { HealthMessage, ProvisionerDaemon } from "#/api/typesGenerated"; import type { HealthMessage, ProvisionerDaemon } from "#/api/typesGenerated";
@@ -8,6 +7,7 @@ import {
TooltipContent, TooltipContent,
TooltipTrigger, TooltipTrigger,
} from "#/components/Tooltip/Tooltip"; } from "#/components/Tooltip/Tooltip";
import { cn } from "#/utils/cn";
import { createDayString } from "#/utils/createDayString"; import { createDayString } from "#/utils/createDayString";
import { ProvisionerTag } from "./ProvisionerTag"; import { ProvisionerTag } from "./ProvisionerTag";
@@ -20,7 +20,6 @@ export const Provisioner: FC<ProvisionerProps> = ({
provisioner, provisioner,
warnings, warnings,
}) => { }) => {
const theme = useTheme();
const daemonScope = provisioner.tags.scope || "organization"; const daemonScope = provisioner.tags.scope || "organization";
const iconScope = const iconScope =
daemonScope === "organization" ? ( daemonScope === "organization" ? (
@@ -36,20 +35,16 @@ export const Provisioner: FC<ProvisionerProps> = ({
return ( return (
<div <div
key={provisioner.name} key={provisioner.name}
css={[ className={cn(
{ "rounded-lg border border-solid border-border text-sm",
borderRadius: 8, isWarning && "border-border-warning",
border: `1px solid ${theme.palette.divider}`, )}
fontSize: 14,
},
isWarning && { borderColor: theme.palette.warning.light },
]}
> >
<header className="p-6 flex items-center justify-between gap-6"> <header className="p-6 flex items-center justify-between gap-6">
<div className="flex items-center gap-6 object-fill"> <div className="flex items-center gap-6 object-fill">
<div className="leading-[160%]"> <div className="leading-relaxed">
<h4 className="font-medium m-0">{provisioner.name}</h4> <h4 className="font-medium m-0">{provisioner.name}</h4>
<span css={{ color: theme.palette.text.secondary }}> <span className="text-content-secondary">
<code>{provisioner.version}</code> <code>{provisioner.version}</code>
</span> </span>
</div> </div>
@@ -71,17 +66,7 @@ export const Provisioner: FC<ProvisionerProps> = ({
</div> </div>
</header> </header>
<div <div className="border-solid border-0 border-t border-border flex items-center justify-between py-3 px-6 text-xs text-content-secondary">
css={{
borderTop: `1px solid ${theme.palette.divider}`,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "8px 24px",
fontSize: 12,
color: theme.palette.text.secondary,
}}
>
{warnings && warnings.length > 0 ? ( {warnings && warnings.length > 0 ? (
<div className="flex flex-col"> <div className="flex flex-col">
{warnings.map((warning) => ( {warnings.map((warning) => (
@@ -92,7 +77,7 @@ export const Provisioner: FC<ProvisionerProps> = ({
<span>No warnings</span> <span>No warnings</span>
)} )}
{provisioner.last_seen_at && ( {provisioner.last_seen_at && (
<span css={{ color: theme.roles.info.text }} data-chromatic="ignore"> <span className="text-content-primary" data-chromatic="ignore">
Last seen {createDayString(provisioner.last_seen_at)} Last seen {createDayString(provisioner.last_seen_at)}
</span> </span>
)} )}
@@ -1,4 +1,3 @@
import { css } from "@emotion/react";
import type { FC } from "react"; import type { FC } from "react";
import type { import type {
DeploymentValues, DeploymentValues,
@@ -60,19 +59,7 @@ export const ExternalAuthSettingsPageView: FC<
</Alert> </Alert>
</div> </div>
<Table <Table className="[&_td]:py-6 [&_td:last-child]:pl-8 [&_th:last-child]:pl-8">
css={css`
& td {
padding-top: 24px;
padding-bottom: 24px;
}
& td:last-child,
& th:last-child {
padding-left: 32px;
}
`}
>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-1/3">ID</TableHead> <TableHead className="w-1/3">ID</TableHead>
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import type { FC } from "react"; import type { FC } from "react";
import { useMutation } from "react-query"; import { useMutation } from "react-query";
import { toast } from "sonner"; import { toast } from "sonner";
@@ -23,17 +22,9 @@ export const Troubleshooting: FC<TroubleshootingProps> = ({
}), }),
}); });
const theme = useTheme();
return ( return (
<> <>
<div <div className="text-sm text-content-secondary leading-relaxed mb-4">
css={{
fontSize: 14,
color: theme.palette.text.secondary,
lineHeight: "160%",
marginBottom: 16,
}}
>
Send a test notification to troubleshoot your notification settings. Send a test notification to troubleshoot your notification settings.
</div> </div>
<div> <div>
+119 -91
View File
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import { import {
CircleAlertIcon, CircleAlertIcon,
CircleCheckIcon, CircleCheckIcon,
@@ -14,27 +13,43 @@ import {
} from "react"; } from "react";
import type { HealthCode, HealthSeverity } from "#/api/typesGenerated"; import type { HealthCode, HealthSeverity } from "#/api/typesGenerated";
import { Link } from "#/components/Link/Link"; import { Link } from "#/components/Link/Link";
import { cn } from "#/utils/cn";
import { docs } from "#/utils/docs"; import { docs } from "#/utils/docs";
import { healthyColor } from "./healthyColor";
const CONTENT_PADDING = 36; const CONTENT_PADDING = 36;
export const Header: FC<HTMLAttributes<HTMLDivElement>> = (props) => { export const Header: FC<HTMLAttributes<HTMLDivElement>> = ({
className,
style,
children,
...props
}) => {
return ( return (
<header <header
className="flex items-center justify-between" className={cn("flex items-center justify-between", className)}
style={{ padding: `36px ${CONTENT_PADDING}px` }} style={{ padding: `36px ${CONTENT_PADDING}px`, ...style }}
{...props} {...props}
/> >
{children}
</header>
); );
}; };
export const HeaderTitle: FC<HTMLAttributes<HTMLDivElement>> = (props) => { export const HeaderTitle: FC<HTMLAttributes<HTMLDivElement>> = ({
className,
children,
...props
}) => {
return ( return (
<h2 <h2
className="m-0 leading-[1.2] text-xl font-medium flex items-center gap-4" className={cn(
"m-0 leading-[1.2] text-xl font-medium flex items-center gap-4",
className,
)}
{...props} {...props}
/> >
{children}
</h2>
); );
}; };
@@ -44,11 +59,18 @@ interface HealthIconProps {
} }
export const HealthIcon: FC<HealthIconProps> = ({ size, severity }) => { export const HealthIcon: FC<HealthIconProps> = ({ size, severity }) => {
const theme = useTheme();
const color = healthyColor(theme, severity);
const Icon = severity === "error" ? CircleAlertIcon : CircleCheckIcon; const Icon = severity === "error" ? CircleAlertIcon : CircleCheckIcon;
return <Icon css={{ width: size, height: size, color }} />; return (
<Icon
className={cn(
severity === "ok" && "text-content-success",
severity === "warning" && "text-content-warning",
severity === "error" && "text-content-destructive",
)}
style={{ width: size, height: size }}
/>
);
}; };
interface HealthyDotProps { interface HealthyDotProps {
@@ -56,72 +78,96 @@ interface HealthyDotProps {
} }
export const HealthyDot: FC<HealthyDotProps> = ({ severity }) => { export const HealthyDot: FC<HealthyDotProps> = ({ severity }) => {
const theme = useTheme();
return ( return (
<div <div
css={{ className={cn(
width: 8, "size-2 rounded-full",
height: 8, severity === "ok" && "bg-content-success",
borderRadius: 9999, severity === "warning" && "bg-content-warning",
backgroundColor: healthyColor(theme, severity), severity === "error" && "bg-content-destructive",
)}
/>
);
};
export const Main: FC<HTMLAttributes<HTMLDivElement>> = ({
className,
style,
children,
...props
}) => {
return (
<div
className={cn("flex flex-col gap-9", className)}
style={{
padding: `0 ${CONTENT_PADDING}px ${CONTENT_PADDING}px`,
...style,
}} }}
/> {...props}
>
{children}
</div>
); );
}; };
export const Main: FC<HTMLAttributes<HTMLDivElement>> = (props) => { export const GridData: FC<HTMLAttributes<HTMLDivElement>> = ({
className,
children,
...props
}) => {
return ( return (
<div <div
className="flex flex-col gap-9" className={cn(
style={{ padding: `0 ${CONTENT_PADDING}px ${CONTENT_PADDING}px` }} "leading-[1.4] w-min whitespace-nowrap",
"grid grid-cols-[auto_auto] gap-3 gap-x-12",
className,
)}
{...props} {...props}
/> >
{children}
</div>
); );
}; };
export const GridData: FC<HTMLAttributes<HTMLDivElement>> = (props) => { export const GridDataLabel: FC<HTMLAttributes<HTMLSpanElement>> = ({
return ( className,
<div children,
className={` ...props
leading-[1.4] w-min whitespace-nowrap }) => {
grid grid-cols-[auto_auto] gap-3 gap-x-12
`}
{...props}
/>
);
};
export const GridDataLabel: FC<HTMLAttributes<HTMLSpanElement>> = (props) => {
const theme = useTheme();
return ( return (
<span <span
css={{ className={cn("text-sm font-medium text-content-secondary", className)}
fontSize: 14,
fontWeight: 500,
color: theme.palette.text.secondary,
}}
{...props} {...props}
/> >
{children}
</span>
); );
}; };
export const GridDataValue: FC<HTMLAttributes<HTMLSpanElement>> = (props) => { export const GridDataValue: FC<HTMLAttributes<HTMLSpanElement>> = ({
const theme = useTheme(); className,
children,
...props
}) => {
return ( return (
<span <span className={cn("text-sm text-content-primary", className)} {...props}>
css={{ {children}
fontSize: 14, </span>
color: theme.palette.text.primary,
}}
{...props}
/>
); );
}; };
export const SectionLabel: FC<HTMLAttributes<HTMLHeadingElement>> = (props) => { export const SectionLabel: FC<HTMLAttributes<HTMLHeadingElement>> = ({
className,
children,
...props
}) => {
return ( return (
<h4 {...props} className="text-sm font-medium m-0 leading-[1.2] mb-4" /> <h4
className={cn("text-sm font-medium m-0 leading-[1.2] mb-4", className)}
{...props}
>
{children}
</h4>
); );
}; };
@@ -129,23 +175,18 @@ type PillProps = React.ComponentPropsWithRef<"div"> & {
icon: ReactElement<HTMLAttributes<HTMLElement>>; icon: ReactElement<HTMLAttributes<HTMLElement>>;
}; };
export const Pill: React.FC<PillProps> = ({ icon, children, ...divProps }) => { export const Pill: React.FC<PillProps> = ({
const theme = useTheme(); className,
icon,
children,
...divProps
}) => {
return ( return (
<div <div
css={{ className={cn(
display: "inline-flex", "inline-flex items-center h-8 rounded-full border border-solid border-border text-xs font-medium p-2 gap-2 cursor-default",
alignItems: "center", className,
height: 32, )}
borderRadius: 9999,
border: `1px solid ${theme.palette.divider}`,
fontSize: 12,
fontWeight: 500,
padding: 8,
gap: 8,
cursor: "default",
}}
{...divProps} {...divProps}
> >
{cloneElement(icon, { className: "size-[14px]" })} {cloneElement(icon, { className: "size-[14px]" })}
@@ -178,16 +219,13 @@ export const BooleanPill: FC<BooleanPillProps> = ({
children, children,
...divProps ...divProps
}) => { }) => {
const theme = useTheme();
const color = value ? theme.roles.success.outline : theme.roles.error.outline;
return ( return (
<Pill <Pill
icon={ icon={
value ? ( value ? (
<CircleCheckIcon css={{ color }} className="size-icon-sm" /> <CircleCheckIcon className="size-icon-sm text-content-success" />
) : ( ) : (
<CircleMinusIcon css={{ color }} className="size-icon-sm" /> <CircleMinusIcon className="size-icon-sm text-content-destructive" />
) )
} }
{...divProps} {...divProps}
@@ -199,21 +237,13 @@ export const BooleanPill: FC<BooleanPillProps> = ({
type LogsProps = HTMLAttributes<HTMLDivElement> & { lines: readonly string[] }; type LogsProps = HTMLAttributes<HTMLDivElement> & { lines: readonly string[] };
export const Logs: FC<LogsProps> = ({ lines, ...divProps }) => { export const Logs: FC<LogsProps> = ({ className, lines, ...divProps }) => {
const theme = useTheme();
return ( return (
<div <div
css={{ className={cn(
fontFamily: "monospace", "font-mono text-[13px] leading-relaxed p-6 bg-surface-secondary overflow-x-auto whitespace-pre-wrap break-all",
fontSize: 13, className,
lineHeight: "160%", )}
padding: 24,
backgroundColor: theme.palette.background.paper,
overflowX: "auto",
whiteSpace: "pre-wrap",
wordBreak: "break-all",
}}
{...divProps} {...divProps}
> >
{lines.map((line, index) => ( {lines.map((line, index) => (
@@ -222,9 +252,7 @@ export const Logs: FC<LogsProps> = ({ lines, ...divProps }) => {
</span> </span>
))} ))}
{lines.length === 0 && ( {lines.length === 0 && (
<span css={{ color: theme.palette.text.secondary }}> <span className="text-content-secondary">No logs available</span>
No logs available
</span>
)} )}
</div> </div>
); );
+2 -16
View File
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import { CodeIcon } from "lucide-react"; import { CodeIcon } from "lucide-react";
import { useOutletContext } from "react-router"; import { useOutletContext } from "react-router";
import type { HealthcheckReport } from "#/api/typesGenerated"; import type { HealthcheckReport } from "#/api/typesGenerated";
@@ -8,7 +7,6 @@ import {
TooltipContent, TooltipContent,
TooltipTrigger, TooltipTrigger,
} from "#/components/Tooltip/Tooltip"; } from "#/components/Tooltip/Tooltip";
import { MONOSPACE_FONT_FAMILY } from "#/theme/constants";
import { pageTitle } from "#/utils/page"; import { pageTitle } from "#/utils/page";
import { import {
Header, Header,
@@ -23,7 +21,6 @@ import { DismissWarningButton } from "./DismissWarningButton";
const WebsocketPage = () => { const WebsocketPage = () => {
const healthStatus = useOutletContext<HealthcheckReport>(); const healthStatus = useOutletContext<HealthcheckReport>();
const { websocket } = healthStatus; const { websocket } = healthStatus;
const theme = useTheme();
return ( return (
<> <>
@@ -65,22 +62,11 @@ const WebsocketPage = () => {
<section> <section>
<SectionLabel>Body</SectionLabel> <SectionLabel>Body</SectionLabel>
<div <div className="bg-surface-secondary border border-solid border-border rounded-lg text-sm p-6 font-mono">
css={{
backgroundColor: theme.palette.background.paper,
border: `1px solid ${theme.palette.divider}`,
borderRadius: 8,
fontSize: 14,
padding: 24,
fontFamily: MONOSPACE_FONT_FAMILY,
}}
>
{websocket.body !== "" ? ( {websocket.body !== "" ? (
websocket.body websocket.body
) : ( ) : (
<span css={{ color: theme.palette.text.secondary }}> <span className="text-content-secondary">No body message</span>
No body message
</span>
)} )}
</div> </div>
</section> </section>
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import { GlobeIcon, HashIcon } from "lucide-react"; import { GlobeIcon, HashIcon } from "lucide-react";
import type { FC } from "react"; import type { FC } from "react";
import { useOutletContext } from "react-router"; import { useOutletContext } from "react-router";
@@ -9,6 +8,7 @@ import {
TooltipContent, TooltipContent,
TooltipTrigger, TooltipTrigger,
} from "#/components/Tooltip/Tooltip"; } from "#/components/Tooltip/Tooltip";
import { cn } from "#/utils/cn";
import { createDayString } from "#/utils/createDayString"; import { createDayString } from "#/utils/createDayString";
import { pageTitle } from "#/utils/page"; import { pageTitle } from "#/utils/page";
import { import {
@@ -26,7 +26,6 @@ const WorkspaceProxyPage: FC = () => {
const healthStatus = useOutletContext<HealthcheckReport>(); const healthStatus = useOutletContext<HealthcheckReport>();
const { workspace_proxy } = healthStatus; const { workspace_proxy } = healthStatus;
const { regions } = workspace_proxy.workspace_proxies; const { regions } = workspace_proxy.workspace_proxies;
const theme = useTheme();
return ( return (
<> <>
@@ -66,15 +65,10 @@ const WorkspaceProxyPage: FC = () => {
return ( return (
<div <div
key={region.id} key={region.id}
css={{ className={cn(
borderRadius: 8, "rounded-lg border border-solid text-sm",
border: `1px solid ${ region.healthy ? "border-border" : "border-border-warning",
region.healthy )}
? theme.palette.divider
: theme.palette.warning.light
}`,
fontSize: 14,
}}
> >
<header className="p-6 flex items-center justify-between gap-6"> <header className="p-6 flex items-center justify-between gap-6">
<div className="flex items-center gap-6"> <div className="flex items-center gap-6">
@@ -85,9 +79,9 @@ const WorkspaceProxyPage: FC = () => {
alt="" alt=""
/> />
</div> </div>
<div className="leading-[160%]"> <div className="leading-relaxed">
<h4 className="font-medium m-0">{region.display_name}</h4> <h4 className="font-medium m-0">{region.display_name}</h4>
<span css={{ color: theme.palette.text.secondary }}> <span className="text-content-secondary">
{region.version} {region.version}
</span> </span>
</div> </div>
@@ -132,17 +126,7 @@ const WorkspaceProxyPage: FC = () => {
</div> </div>
</header> </header>
<div <div className="border-0 border-t border-solid border-border flex items-center justify-between py-3 px-6 text-xs text-content-secondary">
css={{
borderTop: `1px solid ${theme.palette.divider}`,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
padding: "8px 24px",
fontSize: 12,
color: theme.palette.text.secondary,
}}
>
{region.status?.status === "unregistered" ? ( {region.status?.status === "unregistered" ? (
<span>Has not connected yet</span> <span>Has not connected yet</span>
) : warnings.length === 0 && errors.length === 0 ? ( ) : warnings.length === 0 && errors.length === 0 ? (
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import { ExternalLinkIcon, PlusIcon } from "lucide-react"; import { ExternalLinkIcon, PlusIcon } from "lucide-react";
import type { FC } from "react"; import type { FC } from "react";
import { Link } from "react-router"; import { Link } from "react-router";
@@ -24,8 +23,6 @@ export const StarterTemplatePageView: FC<StarterTemplatePageViewProps> = ({
starterTemplate, starterTemplate,
error, error,
}) => { }) => {
const theme = useTheme();
if (error) { if (error) {
return ( return (
<Margins> <Margins>
@@ -72,11 +69,7 @@ export const StarterTemplatePageView: FC<StarterTemplatePageViewProps> = ({
</PageHeader> </PageHeader>
<div <div
css={{ className="bg-surface-secondary border border-solid border-border rounded-lg"
background: theme.palette.background.paper,
border: `1px solid ${theme.palette.divider}`,
borderRadius: 8,
}}
id="readme" id="readme"
> >
<div className="px-10 pt-10 pb-16 max-w-[800px] mx-auto"> <div className="px-10 pt-10 pb-16 max-w-[800px] mx-auto">
@@ -336,7 +336,7 @@ const UsersLatencyPanel: FC<UsersLatencyPanelProps> = ({
.map((row) => ( .map((row) => (
<div <div
key={row.user_id} key={row.user_id}
className="flex justify-between items-center text-[14px] py-2" className="flex justify-between items-center text-sm py-2"
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Avatar fallback={row.username} src={row.avatar_url} /> <Avatar fallback={row.username} src={row.avatar_url} />
@@ -392,7 +392,7 @@ const UsersActivityPanel: FC<UsersActivityPanelProps> = ({
.map((row) => ( .map((row) => (
<div <div
key={row.user_id} key={row.user_id}
className="flex justify-between items-center text-[14px] py-2" className="flex justify-between items-center text-sm py-2"
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Avatar fallback={row.username} src={row.avatar_url} /> <Avatar fallback={row.username} src={row.avatar_url} />
@@ -527,7 +527,7 @@ const TemplateParametersUsagePanel: FC<TemplateParametersUsagePanelProps> = ({
> >
<div className="flex-1"> <div className="flex-1">
<div className="font-medium">{label}</div> <div className="font-medium">{label}</div>
<p className="text-[14px] m-0 text-content-secondary max-w-[400px]"> <p className="text-sm m-0 text-content-secondary max-w-[400px]">
{parameter.description} {parameter.description}
</p> </p>
</div> </div>
@@ -706,7 +706,7 @@ const PanelTitle: FC<HTMLAttributes<HTMLDivElement>> = ({
...attrs ...attrs
}) => { }) => {
return ( return (
<div {...attrs} className={cn("text-[14px] font-medium", className)}> <div {...attrs} className={cn("text-sm font-medium", className)}>
{children} {children}
</div> </div>
); );
+2 -10
View File
@@ -192,16 +192,8 @@ const TerminalPage: FC = () => {
</div> </div>
{latency && isDebugging && ( {latency && isDebugging && (
<span <span className="absolute bottom-6 right-6 text-content-disabled text-sm">
css={{ Latency: {latency.latencyMS.toFixed(0)}ms{" "}
position: "absolute",
bottom: 24,
right: 24,
color: theme.palette.text.disabled,
fontSize: 14,
}}
>
Latency: {latency.latencyMS.toFixed(0)}ms
</span> </span>
)} )}
@@ -1,4 +1,3 @@
import { useTheme } from "@emotion/react";
import { type FC, type ReactNode, useState } from "react"; import { type FC, type ReactNode, useState } from "react";
import type { AlertProps } from "#/components/Alert/Alert"; import type { AlertProps } from "#/components/Alert/Alert";
import { Button, type ButtonProps } from "#/components/Button/Button"; import { Button, type ButtonProps } from "#/components/Button/Button";
@@ -9,6 +8,7 @@ import {
PopoverTrigger, PopoverTrigger,
} from "#/components/Popover/Popover"; } from "#/components/Popover/Popover";
import type { ThemeRole } from "#/theme/roles"; import type { ThemeRole } from "#/theme/roles";
import { cn } from "#/utils/cn";
export type NotificationItem = { export type NotificationItem = {
title: string; title: string;
@@ -23,13 +23,55 @@ type NotificationsProps = {
icon: ReactNode; icon: ReactNode;
}; };
// Maps a ThemeRole severity to Tailwind classes for the role's outline
// color. These are the closest semantic matches available in the design
// token system.
const severityStyles: Record<ThemeRole, { svgColor: string; border: string }> =
{
error: {
svgColor: "[&_svg]:text-border-destructive",
border: "border-border-destructive",
},
warning: {
svgColor: "[&_svg]:text-border-warning",
border: "border-border-warning",
},
notice: {
svgColor: "[&_svg]:text-border-pending",
border: "border-border-pending",
},
info: {
svgColor: "[&_svg]:text-content-secondary",
border: "border-border",
},
success: {
svgColor: "[&_svg]:text-border-success",
border: "border-border-success",
},
active: {
svgColor: "[&_svg]:text-border-pending",
border: "border-border-pending",
},
inactive: {
svgColor: "[&_svg]:text-content-disabled",
border: "border-border",
},
danger: {
svgColor: "[&_svg]:text-border-warning",
border: "border-border-warning",
},
preview: {
svgColor: "[&_svg]:text-border-purple",
border: "border-border-purple",
},
};
export const Notifications: FC<NotificationsProps> = ({ export const Notifications: FC<NotificationsProps> = ({
items, items,
severity, severity,
icon, icon,
}) => { }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const theme = useTheme();
return ( return (
<Popover open={isOpen} onOpenChange={setIsOpen}> <Popover open={isOpen} onOpenChange={setIsOpen}>
@@ -50,10 +92,10 @@ export const Notifications: FC<NotificationsProps> = ({
<PopoverContent <PopoverContent
align="end" align="end"
collisionPadding={16} collisionPadding={16}
className="max-w-[400px] p-0 w-auto bg-surface-secondary border-surface-quaternary text-sm text-content-primary" className={cn(
style={{ "max-w-[400px] p-0 w-auto bg-surface-secondary text-sm text-content-primary",
borderColor: theme.roles[severity].outline, severityStyles[severity].border,
}} )}
> >
{items.map((n) => ( {items.map((n) => (
<NotificationItem notification={n} key={n.title} /> <NotificationItem notification={n} key={n.title} />
@@ -76,10 +118,10 @@ const NotificationPill: FC<NotificationPillProps> = ({
return ( return (
<Pill <Pill
icon={icon} icon={icon}
css={(theme) => ({ className={cn(
"& svg": { color: theme.roles[severity].outline }, severityStyles[severity].svgColor,
borderColor: isOpen ? theme.roles[severity].outline : undefined, isOpen && severityStyles[severity].border,
})} )}
> >
{items.length} {items.length}
</Pill> </Pill>
@@ -196,10 +196,7 @@ export const WorkspacesPageView: FC<WorkspacesPageViewProps> = ({
{pageNumberIsInvalid ? ( {pageNumberIsInvalid ? (
<EmptyState <EmptyState
css={(theme) => ({ className="border border-solid border-border rounded-lg"
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadius,
})}
message="Page not found" message="Page not found"
description="The page you are trying to access does not exist." description="The page you are trying to access does not exist."
cta={ cta={
@@ -207,7 +207,7 @@ export const WorkspacesTable: FC<WorkspacesTableProps> = ({
/> />
<AvatarData <AvatarData
title={ title={
<div className="flex items-center gap-0.5"> <div className="flex items-center gap-1">
<span className="whitespace-nowrap"> <span className="whitespace-nowrap">
{workspace.name} {workspace.name}
</span> </span>