Skip to content

Commit 5b5fbbe

Browse files
authored
fix: implement proper overflow behavior for workspace history (#19340)
Before: https://github.com/user-attachments/assets/2f1ff75c-4916-4d0a-a657-004d46691ea0 After: https://github.com/user-attachments/assets/a8e575b5-84f9-4eea-b318-93d2a3d60aa5 Also converts a lot of emotion components to tailwind
1 parent 734299d commit 5b5fbbe

File tree

5 files changed

+184
-290
lines changed

5 files changed

+184
-290
lines changed
Lines changed: 26 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
1-
import { type Interpolation, type Theme, useTheme } from "@emotion/react";
21
import type { ComponentProps, FC, HTMLAttributes } from "react";
32
import { Link, type LinkProps } from "react-router";
3+
import { cn } from "utils/cn";
44
import { TopbarIconButton } from "./Topbar";
55

66
export const Sidebar: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
7-
const theme = useTheme();
87
return (
98
<div
10-
css={{
11-
width: 260,
12-
borderRight: `1px solid ${theme.palette.divider}`,
13-
height: "100%",
14-
overflow: "auto",
15-
flexShrink: 0,
16-
padding: "8px 0",
17-
display: "flex",
18-
flexDirection: "column",
19-
gap: 1,
20-
}}
9+
// TODO: Remove extra border classes once MUI is removed
10+
className="flex flex-col gap-px w-64 border-solid border-0 border-r border-r-border h-full py-2 shrink-0 overflow-y-auto"
2111
{...props}
2212
/>
2313
);
2414
};
2515

26-
export const SidebarLink: FC<LinkProps> = (props) => {
27-
return <Link css={styles.sidebarItem} {...props} />;
16+
export const SidebarLink: FC<LinkProps> = ({ className, ...props }) => {
17+
return (
18+
<Link
19+
className={cn(
20+
"text-[13px] text-content-primary py-2 px-4 text-left bg-transparent hover:divide-surface-tertiary cursor-pointer border-0 no-underline",
21+
className,
22+
)}
23+
{...props}
24+
/>
25+
);
2826
};
2927

3028
interface SidebarItemProps extends HTMLAttributes<HTMLButtonElement> {
@@ -33,21 +31,16 @@ interface SidebarItemProps extends HTMLAttributes<HTMLButtonElement> {
3331

3432
export const SidebarItem: FC<SidebarItemProps> = ({
3533
isActive,
34+
className,
3635
...buttonProps
3736
}) => {
38-
const theme = useTheme();
39-
4037
return (
4138
<button
42-
css={[
43-
styles.sidebarItem,
44-
{ opacity: "0.75", "&:hover": { opacity: 1 } },
45-
isActive && {
46-
background: theme.palette.action.selected,
47-
opacity: 1,
48-
pointerEvents: "none",
49-
},
50-
]}
39+
className={cn(
40+
"text-[13px] text-content-primary py-2 px-4 text-left bg-transparent hover:divide-surface-tertiary opacity-75 hover:opacity-100 cursor-pointer border-0",
41+
isActive && "opacity-100 bg-surface-tertiary",
42+
className,
43+
)}
5144
{...buttonProps}
5245
/>
5346
);
@@ -56,15 +49,7 @@ export const SidebarItem: FC<SidebarItemProps> = ({
5649
export const SidebarCaption: FC<HTMLAttributes<HTMLSpanElement>> = (props) => {
5750
return (
5851
<span
59-
css={{
60-
fontSize: 10,
61-
lineHeight: 1.2,
62-
padding: "12px 16px",
63-
display: "block",
64-
textTransform: "uppercase",
65-
fontWeight: 500,
66-
letterSpacing: "0.1em",
67-
}}
52+
className="text-[10px] leading-tight py-3 px-4 uppercase font-medium text-content-primary tracking-widest"
6853
{...props}
6954
/>
7055
);
@@ -76,49 +61,17 @@ interface SidebarIconButton extends ComponentProps<typeof TopbarIconButton> {
7661

7762
export const SidebarIconButton: FC<SidebarIconButton> = ({
7863
isActive,
64+
className,
7965
...buttonProps
8066
}) => {
8167
return (
8268
<TopbarIconButton
83-
css={[
84-
{ opacity: 0.75, "&:hover": { opacity: 1 } },
85-
isActive && styles.activeSidebarIconButton,
86-
]}
69+
className={cn(
70+
"opacity-75 hover:opacity-100 border-0 border-x-2 border-x-transparent border-solid",
71+
isActive && "opacity-100 relative border-l-sky-400",
72+
className,
73+
)}
8774
{...buttonProps}
8875
/>
8976
);
9077
};
91-
92-
const styles = {
93-
sidebarItem: (theme) => ({
94-
fontSize: 13,
95-
lineHeight: 1.2,
96-
color: theme.palette.text.primary,
97-
textDecoration: "none",
98-
padding: "8px 16px",
99-
display: "block",
100-
textAlign: "left",
101-
background: "none",
102-
border: 0,
103-
cursor: "pointer",
104-
105-
"&:hover": {
106-
backgroundColor: theme.palette.action.hover,
107-
},
108-
}),
109-
110-
activeSidebarIconButton: (theme) => ({
111-
opacity: 1,
112-
position: "relative",
113-
"&::before": {
114-
content: '""',
115-
position: "absolute",
116-
left: 0,
117-
top: 0,
118-
bottom: 0,
119-
width: 2,
120-
backgroundColor: theme.palette.primary.main,
121-
height: "100%",
122-
},
123-
}),
124-
} satisfies Record<string, Interpolation<Theme>>;

site/src/modules/dashboard/DashboardLayout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ export const DashboardLayout: FC = () => {
2323
{canViewDeployment && <LicenseBanner />}
2424
<AnnouncementBanners />
2525

26-
<div className="flex flex-col min-h-full">
26+
<div className="flex flex-col h-screen">
2727
<Navbar />
2828

29-
<div className="flex flex-col flex-1 pb-12">
29+
<div className="flex flex-col flex-1 min-h-0">
3030
<Suspense fallback={<Loader />}>
3131
<Outlet />
3232
</Suspense>

site/src/modules/dashboard/Navbar/NavbarView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export const NavbarView: FC<NavbarViewProps> = ({
5151
const webPush = useWebpushNotifications();
5252

5353
return (
54-
<div className="border-0 border-b border-solid h-[72px] flex items-center leading-none px-6">
54+
<div className="border-0 border-b border-solid h-[72px] min-h-[72px] flex items-center leading-none px-6">
5555
<NavLink to="/workspaces">
5656
{logo_url ? (
5757
<ExternalImage className="h-7" src={logo_url} alt="Custom Logo" />

site/src/pages/WorkspacePage/HistorySidebar.tsx

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
SidebarItem,
99
SidebarLink,
1010
} from "components/FullPageLayout/Sidebar";
11+
import { ScrollArea } from "components/ScrollArea/ScrollArea";
1112
import { Spinner } from "components/Spinner/Spinner";
1213
import {
1314
WorkspaceBuildData,
@@ -30,36 +31,40 @@ export const HistorySidebar: FC<HistorySidebarProps> = ({ workspace }) => {
3031
return (
3132
<Sidebar>
3233
<SidebarCaption>History</SidebarCaption>
33-
{builds
34-
? builds.map((build) => (
35-
<SidebarLink
36-
target="_blank"
37-
key={build.id}
38-
to={`/@${build.workspace_owner_name}/${build.workspace_name}/builds/${build.build_number}`}
39-
>
40-
<WorkspaceBuildData build={build} />
41-
</SidebarLink>
42-
))
43-
: Array.from({ length: 15 }, (_, i) => (
44-
<SidebarItem key={i}>
45-
<WorkspaceBuildDataSkeleton />
46-
</SidebarItem>
47-
))}
48-
{buildsQuery.hasNextPage && (
49-
<div css={{ padding: 16 }}>
50-
<Button
51-
onClick={() => buildsQuery.fetchNextPage()}
52-
disabled={buildsQuery.isFetchingNextPage}
53-
variant="outline"
54-
className="w-full"
55-
>
56-
<Spinner loading={buildsQuery.isFetchingNextPage}>
57-
<ArrowDownwardOutlined />
58-
</Spinner>
59-
Show more builds
60-
</Button>
34+
<ScrollArea>
35+
<div className="flex flex-col gap-px">
36+
{builds
37+
? builds.map((build) => (
38+
<SidebarLink
39+
target="_blank"
40+
key={build.id}
41+
to={`/@${build.workspace_owner_name}/${build.workspace_name}/builds/${build.build_number}`}
42+
>
43+
<WorkspaceBuildData build={build} />
44+
</SidebarLink>
45+
))
46+
: Array.from({ length: 15 }, (_, i) => (
47+
<SidebarItem key={i}>
48+
<WorkspaceBuildDataSkeleton />
49+
</SidebarItem>
50+
))}
51+
{buildsQuery.hasNextPage && (
52+
<div css={{ padding: 16 }}>
53+
<Button
54+
onClick={() => buildsQuery.fetchNextPage()}
55+
disabled={buildsQuery.isFetchingNextPage}
56+
variant="outline"
57+
className="w-full"
58+
>
59+
<Spinner loading={buildsQuery.isFetchingNextPage}>
60+
<ArrowDownwardOutlined />
61+
</Spinner>
62+
Show more builds
63+
</Button>
64+
</div>
65+
)}
6166
</div>
62-
)}
67+
</ScrollArea>
6368
</Sidebar>
6469
);
6570
};

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy