mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
feat: remove mui from <AppearanceSettingsPage /> (#22368)
This migrates the content from using `MUI` to the new standard `shadcn` components on the `<AppearanceSettingsPage />`. Things should work exactly how they did before, but with a new shinier coat of paint. | Old | New | | --- | --- | | <img width="1019" height="651" alt="APPEARANCE_SETTINGS_OLD" src="https://github.com/user-attachments/assets/d514ea17-f669-4343-99c1-9c8896ae85d8" /> | <img width="1019" height="653" alt="APPEARANCE_SETTINGS_NEW" src="https://github.com/user-attachments/assets/424616af-c975-43fa-bd4a-13d0b0fe136b" /> |
This commit is contained in:
+12
-46
@@ -1,10 +1,8 @@
|
||||
import { type CSSObject, useTheme } from "@emotion/react";
|
||||
import Link from "@mui/material/Link";
|
||||
import type { BannerConfig } from "api/typesGenerated";
|
||||
import { Button } from "components/Button/Button";
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
|
||||
import { EmptyState } from "components/EmptyState/EmptyState";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { Link } from "components/Link/Link";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -27,7 +25,6 @@ interface AnnouncementBannersettingsProps {
|
||||
export const AnnouncementBannerSettings: FC<
|
||||
AnnouncementBannersettingsProps
|
||||
> = ({ isEntitled, announcementBanners, onSubmit }) => {
|
||||
const theme = useTheme();
|
||||
const [banners, setBanners] = useState(announcementBanners);
|
||||
const [editingBannerId, setEditingBannerId] = useState<number | null>(null);
|
||||
const [deletingBannerId, setDeletingBannerId] = useState<number | null>(null);
|
||||
@@ -65,29 +62,10 @@ export const AnnouncementBannerSettings: FC<
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
css={{
|
||||
borderRadius: 8,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
marginTop: 32,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div className="mt-8 overflow-hidden rounded-lg border border-solid border-border">
|
||||
<div className="p-6">
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<h3
|
||||
css={{
|
||||
fontSize: 20,
|
||||
margin: 0,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Announcement Banners
|
||||
</h3>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<h3 className="m-0 text-xl font-semibold">Announcement Banners</h3>
|
||||
<Button
|
||||
disabled={!isEntitled}
|
||||
onClick={() => addBanner()}
|
||||
@@ -96,18 +74,12 @@ export const AnnouncementBannerSettings: FC<
|
||||
<PlusIcon />
|
||||
New
|
||||
</Button>
|
||||
</Stack>
|
||||
<div
|
||||
css={{
|
||||
color: theme.palette.text.secondary,
|
||||
fontSize: 14,
|
||||
marginTop: 8,
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
<div className="mt-2 text-sm text-content-secondary">
|
||||
Display message banners to all users.
|
||||
</div>
|
||||
|
||||
<div css={[theme.typography.body2 as CSSObject, { paddingTop: 16 }]}>
|
||||
<div className="pt-4 text-sm">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
@@ -147,20 +119,14 @@ export const AnnouncementBannerSettings: FC<
|
||||
</div>
|
||||
|
||||
{!isEntitled && (
|
||||
<footer
|
||||
css={[
|
||||
theme.typography.body2 as CSSObject,
|
||||
{
|
||||
background: theme.palette.background.paper,
|
||||
padding: "16px 24px",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<footer className="bg-surface-secondary px-6 py-4 text-sm">
|
||||
<div className="text-content-secondary">
|
||||
<p>
|
||||
Your license does not include Service Banners.{" "}
|
||||
<Link href="mailto:sales@coder.com">Contact sales</Link> to
|
||||
learn more.
|
||||
<Link href="mailto:sales@coder.com" showExternalIcon={false}>
|
||||
Contact sales
|
||||
</Link>{" "}
|
||||
to learn more.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
+30
-46
@@ -1,5 +1,3 @@
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import type { UpdateAppearanceConfig } from "api/typesGenerated";
|
||||
import {
|
||||
Badges,
|
||||
@@ -7,6 +5,12 @@ import {
|
||||
PremiumBadge,
|
||||
} from "components/Badges/Badges";
|
||||
import { Button } from "components/Button/Button";
|
||||
import { Input } from "components/Input/Input";
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "components/InputGroup/InputGroup";
|
||||
import { PopoverPaywall } from "components/Paywall/PopoverPaywall";
|
||||
import {
|
||||
SettingsHeader,
|
||||
@@ -98,15 +102,11 @@ export const AppearanceSettingsPageView: FC<
|
||||
onSubmit={applicationNameForm.handleSubmit}
|
||||
button={!isEntitled && <Button disabled>Submit</Button>}
|
||||
>
|
||||
<TextField
|
||||
<Input
|
||||
{...applicationNameFieldHelpers("application_name")}
|
||||
defaultValue={appearance.application_name}
|
||||
fullWidth
|
||||
placeholder='Leave empty to display "Coder".'
|
||||
disabled={!isEntitled}
|
||||
inputProps={{
|
||||
"aria-label": "Application name",
|
||||
}}
|
||||
aria-label="Application name"
|
||||
/>
|
||||
</Fieldset>
|
||||
|
||||
@@ -122,44 +122,28 @@ export const AppearanceSettingsPageView: FC<
|
||||
onSubmit={logoForm.handleSubmit}
|
||||
button={!isEntitled && <Button disabled>Submit</Button>}
|
||||
>
|
||||
<TextField
|
||||
{...logoFieldHelpers("logo_url")}
|
||||
defaultValue={appearance.logo_url}
|
||||
fullWidth
|
||||
placeholder="Leave empty to display the Coder logo."
|
||||
disabled={!isEntitled}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment
|
||||
position="end"
|
||||
css={{
|
||||
width: 24,
|
||||
height: 24,
|
||||
|
||||
"& img": {
|
||||
maxWidth: "100%",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
src={logoForm.values.logo_url}
|
||||
// This prevent browser to display the ugly error icon if the
|
||||
// image path is wrong or user didn't finish typing the url
|
||||
onError={(e) => {
|
||||
e.currentTarget.style.display = "none";
|
||||
}}
|
||||
onLoad={(e) => {
|
||||
e.currentTarget.style.display = "inline";
|
||||
}}
|
||||
/>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
inputProps={{
|
||||
"aria-label": "Logo URL",
|
||||
}}
|
||||
/>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
{...logoFieldHelpers("logo_url")}
|
||||
placeholder="Leave empty to display the Coder logo."
|
||||
disabled={!isEntitled}
|
||||
aria-label="Logo URL"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<img
|
||||
alt=""
|
||||
src={logoForm.values.logo_url}
|
||||
className="h-6 w-6 max-w-full object-contain"
|
||||
// Hide broken image icon while users type incomplete URLs.
|
||||
onError={(e) => {
|
||||
e.currentTarget.style.display = "none";
|
||||
}}
|
||||
onLoad={(e) => {
|
||||
e.currentTarget.style.display = "inline";
|
||||
}}
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Fieldset>
|
||||
|
||||
<AnnouncementBannerSettings
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { type CSSObject, useTheme } from "@emotion/react";
|
||||
import { Button } from "components/Button/Button";
|
||||
import type { FC, FormEventHandler, JSX, ReactNode } from "react";
|
||||
|
||||
@@ -21,56 +20,20 @@ export const Fieldset: FC<FieldsetProps> = ({
|
||||
onSubmit,
|
||||
isSubmitting,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<form
|
||||
css={{
|
||||
borderRadius: 8,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
marginTop: 32,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
className="mt-8 overflow-hidden rounded-lg border border-solid border-border"
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<header css={{ padding: 24 }}>
|
||||
<div
|
||||
css={{
|
||||
fontSize: 20,
|
||||
margin: 0,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
<header className="p-6">
|
||||
<div className="text-xl font-semibold">{title}</div>
|
||||
{subtitle && (
|
||||
<div
|
||||
css={{
|
||||
color: theme.palette.text.secondary,
|
||||
fontSize: 14,
|
||||
marginTop: 8,
|
||||
}}
|
||||
>
|
||||
{subtitle}
|
||||
</div>
|
||||
<div className="mt-2 text-sm text-content-secondary">{subtitle}</div>
|
||||
)}
|
||||
<div css={[theme.typography.body2 as CSSObject, { paddingTop: 16 }]}>
|
||||
{children}
|
||||
</div>
|
||||
<div className="pt-4 text-sm">{children}</div>
|
||||
</header>
|
||||
<footer
|
||||
css={[
|
||||
theme.typography.body2 as CSSObject,
|
||||
{
|
||||
background: theme.palette.background.paper,
|
||||
padding: "16px 24px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<div css={{ color: theme.palette.text.secondary }}>{validation}</div>
|
||||
<footer className="flex items-center justify-between bg-surface-secondary px-6 py-4 text-sm">
|
||||
<div className="text-content-secondary">{validation}</div>
|
||||
{button || (
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
Submit
|
||||
|
||||
Reference in New Issue
Block a user