mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
chore: improve scroll behavior of DashboardLayout wrapped pages (#19396)
Updates the the `DashboardLayout` to create a singular scroll area between the top nav bar and the deployment banner on the bottom. Also improves the scroll behavior of the org settings pages. <img width="2122" height="1413" alt="CleanShot 2025-08-18 at 13 53 01" src="https://github.com/user-attachments/assets/a9920509-69e7-471d-ac0d-853cb212fcae" /> https://github.com/user-attachments/assets/128be43d-433f-4a0f-af5b-bbfb7d646345
This commit is contained in:
@@ -5,10 +5,11 @@ import { cn } from "utils/cn";
|
||||
|
||||
interface SidebarProps {
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const Sidebar: FC<SidebarProps> = ({ children }) => {
|
||||
return <nav className="w-60 flex-shrink-0">{children}</nav>;
|
||||
export const Sidebar: FC<SidebarProps> = ({ className, children }) => {
|
||||
return <nav className={cn("w-60 flex-shrink-0", className)}>{children}</nav>;
|
||||
};
|
||||
|
||||
interface SidebarHeaderProps {
|
||||
|
||||
@@ -23,10 +23,10 @@ export const DashboardLayout: FC = () => {
|
||||
{canViewDeployment && <LicenseBanner />}
|
||||
<AnnouncementBanners />
|
||||
|
||||
<div className="flex flex-col min-h-screen">
|
||||
<div className="flex flex-col h-screen justify-between">
|
||||
<Navbar />
|
||||
|
||||
<div className="flex flex-col flex-1 min-h-0 pb-12">
|
||||
<div className="flex flex-col flex-1 min-h-0 overflow-y-auto">
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
|
||||
@@ -91,7 +91,7 @@ const OrganizationSettingsLayout: FC = () => {
|
||||
organizationPermissions,
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div className="flex flex-col flex-1 min-h-0">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
@@ -121,8 +121,8 @@ const OrganizationSettingsLayout: FC = () => {
|
||||
)}
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
<hr className="h-px border-none bg-border" />
|
||||
<div className="px-10 max-w-screen-2xl">
|
||||
<div className="h-px border-none bg-border" />
|
||||
<div className="flex flex-col flex-1 min-h-0 pl-10">
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
|
||||
@@ -13,7 +13,7 @@ export const OrganizationSidebar: FC = () => {
|
||||
useOrganizationSettings();
|
||||
|
||||
return (
|
||||
<BaseSidebar>
|
||||
<BaseSidebar className="pt-10">
|
||||
<OrganizationSidebarView
|
||||
activeOrganization={organization}
|
||||
orgPermissions={organizationPermissions}
|
||||
|
||||
@@ -5,9 +5,9 @@ import { OrganizationSidebar } from "./OrganizationSidebar";
|
||||
|
||||
const OrganizationSidebarLayout: FC = () => {
|
||||
return (
|
||||
<div className="flex flex-row gap-28 py-10">
|
||||
<div className="flex flex-row flex-1 min-h-0 w-full">
|
||||
<OrganizationSidebar />
|
||||
<main css={{ flexGrow: 1 }}>
|
||||
<main className="flex flex-col items-center flex-1 min-h-0 h-full overflow-y-auto w-full px-10 pt-10">
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
|
||||
@@ -57,7 +57,7 @@ export const AuditPageView: FC<AuditPageViewProps> = ({
|
||||
const isEmpty = !isLoading && auditLogs?.length === 0;
|
||||
|
||||
return (
|
||||
<Margins>
|
||||
<Margins className="pb-12">
|
||||
<PageHeader>
|
||||
<PageHeaderTitle>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
|
||||
@@ -56,7 +56,7 @@ export const ConnectionLogPageView: FC<ConnectionLogPageViewProps> = ({
|
||||
const isEmpty = !isLoading && connectionLogs?.length === 0;
|
||||
|
||||
return (
|
||||
<Margins>
|
||||
<Margins className="pb-12">
|
||||
<PageHeader>
|
||||
<PageHeaderTitle>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
|
||||
@@ -24,7 +24,7 @@ export const CreateTemplateGalleryPageView: FC<
|
||||
CreateTemplateGalleryPageViewProps
|
||||
> = ({ starterTemplatesByTag, error }) => {
|
||||
return (
|
||||
<Margins>
|
||||
<Margins className="pb-12">
|
||||
<PageHeader
|
||||
actions={
|
||||
<Button asChild size="sm" variant="outline">
|
||||
|
||||
@@ -76,7 +76,7 @@ const GroupsPage: FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full max-w-screen-2xl pb-10">
|
||||
{helmet}
|
||||
|
||||
<Stack
|
||||
@@ -107,7 +107,7 @@ const GroupsPage: FC = () => {
|
||||
canCreateGroup={permissions.createGroup}
|
||||
groupsEnabled={groupsEnabled}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ const CustomRolesPage: FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full max-w-screen-2xl pb-10">
|
||||
<Helmet>
|
||||
<title>
|
||||
{pageTitle(
|
||||
@@ -116,7 +116,7 @@ const CustomRolesPage: FC = () => {
|
||||
}}
|
||||
/>
|
||||
</RequirePermission>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ const IdpSyncPage: FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full max-w-screen-2xl pb-10">
|
||||
{helmet}
|
||||
|
||||
<div className="flex flex-col gap-12">
|
||||
@@ -182,7 +182,7 @@ const IdpSyncPage: FC = () => {
|
||||
</Cond>
|
||||
</ChooseOne>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { Interpolation, Theme } from "@emotion/react";
|
||||
import { getErrorMessage } from "api/errors";
|
||||
import { groupsByUserIdInOrganization } from "api/queries/groups";
|
||||
import {
|
||||
@@ -156,9 +155,7 @@ const OrganizationMembersPage: FC = () => {
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p css={styles.test}>
|
||||
Are you sure you want to remove this member?
|
||||
</p>
|
||||
<p className="pb-5">Are you sure you want to remove this member?</p>
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
@@ -166,10 +163,4 @@ const OrganizationMembersPage: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
test: {
|
||||
paddingBottom: 20,
|
||||
},
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
export default OrganizationMembersPage;
|
||||
|
||||
@@ -81,7 +81,7 @@ export const OrganizationMembersPageView: FC<
|
||||
updateMemberRoles,
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="w-full max-w-screen-2xl pb-10">
|
||||
<SettingsHeader>
|
||||
<SettingsHeaderTitle>Members</SettingsHeaderTitle>
|
||||
</SettingsHeader>
|
||||
|
||||
+2
-2
@@ -99,7 +99,7 @@ const OrganizationProvisionerJobsPageView: FC<
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full max-w-screen-2xl pb-10">
|
||||
<Helmet>
|
||||
<title>
|
||||
{pageTitle(
|
||||
@@ -227,7 +227,7 @@ const OrganizationProvisionerJobsPageView: FC<
|
||||
</TableBody>
|
||||
</Table>
|
||||
</section>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ export const OrganizationProvisionerKeysPageView: FC<
|
||||
OrganizationProvisionerKeysPageViewProps
|
||||
> = ({ showPaywall, provisionerKeyDaemons, error, onRetry }) => {
|
||||
return (
|
||||
<section>
|
||||
<section className="w-full max-w-screen-2xl pb-10">
|
||||
<SettingsHeader>
|
||||
<SettingsHeaderTitle>Provisioner Keys</SettingsHeaderTitle>
|
||||
<SettingsHeaderDescription>
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ export const OrganizationProvisionersPageView: FC<
|
||||
onRetry,
|
||||
}) => {
|
||||
return (
|
||||
<section>
|
||||
<section className="w-full max-w-screen-2xl pb-10">
|
||||
<SettingsHeader>
|
||||
<SettingsHeaderTitle>Provisioners</SettingsHeaderTitle>
|
||||
<SettingsHeaderDescription>
|
||||
|
||||
@@ -68,7 +68,7 @@ export const OrganizationSettingsPageView: FC<
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="w-full max-w-screen-2xl pb-10">
|
||||
<SettingsHeader>
|
||||
<SettingsHeaderTitle>Settings</SettingsHeaderTitle>
|
||||
</SettingsHeader>
|
||||
|
||||
@@ -108,7 +108,7 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
|
||||
|
||||
if (error || workspacePermissionsQuery.error) {
|
||||
return (
|
||||
<div css={{ margin: 16 }}>
|
||||
<div className="p-4">
|
||||
<ErrorAlert error={error} />
|
||||
</div>
|
||||
);
|
||||
@@ -119,7 +119,7 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="pb-12">
|
||||
<TemplatePageHeader
|
||||
template={data.template}
|
||||
activeVersion={data.activeVersion}
|
||||
@@ -166,6 +166,6 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
|
||||
<Suspense fallback={<Loader />}>{children}</Suspense>
|
||||
</TemplateLayoutContext.Provider>
|
||||
</Margins>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -205,7 +205,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({
|
||||
const isEmpty = templates && templates.length === 0;
|
||||
|
||||
return (
|
||||
<Margins>
|
||||
<Margins className="pb-12">
|
||||
<PageHeader
|
||||
actions={
|
||||
canCreateTemplates && (
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
terminalFontLabels,
|
||||
terminalFonts,
|
||||
} from "theme/constants";
|
||||
import { cn } from "utils/cn";
|
||||
import { Section } from "../Section";
|
||||
|
||||
interface AppearanceFormProps {
|
||||
@@ -164,7 +165,7 @@ const AutoThemePreviewButton: FC<AutoThemePreviewButtonProps> = ({
|
||||
onChange={onSelect}
|
||||
css={{ ...visuallyHidden }}
|
||||
/>
|
||||
<label htmlFor={displayName} className={className}>
|
||||
<label htmlFor={displayName} className={cn("relative", className)}>
|
||||
<ThemePreview
|
||||
css={{
|
||||
// This half is absolute to not advance the layout (which would offset the second half)
|
||||
|
||||
Reference in New Issue
Block a user