Skip to content

Commit 7bfb714

Browse files
committed
breadcrumbs: remove styled and simplify
1 parent 4ae298e commit 7bfb714

File tree

2 files changed

+64
-97
lines changed

2 files changed

+64
-97
lines changed

static/app/components/breadcrumbs.stories.tsx

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,18 @@ export default Storybook.story('Breadcrumbs', story => {
1616
crumbs={[
1717
{label: 'Organization', to: '/organizations/sentry/'},
1818
{label: 'Projects', to: '/organizations/sentry/projects/'},
19-
{label: 'Project Settings', to: '/settings/projects/javascript/'},
19+
{
20+
label: 'Project Settings',
21+
to: '/settings/projects/javascript/',
22+
preservePageFilters: true,
23+
},
2024
{label: 'General', to: null},
2125
]}
2226
/>
2327
</Storybook.SizingWindow>
2428
</Fragment>
2529
));
2630

27-
story('With Last Item Linked', () => (
28-
<Fragment>
29-
<p>
30-
Set <Storybook.JSXProperty name="linkLastItem" value /> to make the last
31-
breadcrumb clickable.
32-
</p>
33-
<Storybook.SizingWindow display="block">
34-
<Breadcrumbs
35-
linkLastItem
36-
crumbs={[
37-
{label: 'Organization', to: '/organizations/sentry/'},
38-
{label: 'Projects', to: '/organizations/sentry/projects/'},
39-
{label: 'All Projects', to: '/organizations/sentry/projects/all/'},
40-
]}
41-
/>
42-
</Storybook.SizingWindow>
43-
</Fragment>
44-
));
45-
4631
story('Page Filter Preservation', () => (
4732
<Fragment>
4833
<p>
Lines changed: 59 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
import {Fragment} from 'react';
2-
import type {Theme} from '@emotion/react';
3-
import {css} from '@emotion/react';
4-
import styled from '@emotion/styled';
2+
3+
import {Flex} from '@sentry/scraps/layout';
4+
import {Text} from '@sentry/scraps/text';
55

66
import {Chevron} from 'sentry/components/chevron';
77
import type {LinkProps} from 'sentry/components/core/link';
88
import {Link} from 'sentry/components/core/link';
99
import GlobalSelectionLink from 'sentry/components/globalSelectionLink';
10-
import {space} from 'sentry/styles/space';
11-
12-
const BreadcrumbList = styled('nav')`
13-
display: flex;
14-
align-items: center;
15-
padding: ${space(1)} 0;
16-
`;
1710

1811
export interface Crumb {
1912
/**
@@ -39,103 +32,92 @@ export interface Crumb {
3932
to?: LinkProps['to'] | null;
4033
}
4134

42-
interface Props extends React.HTMLAttributes<HTMLDivElement> {
43-
/**
44-
* Array of crumbs that will be rendered
45-
*/
35+
interface BreadcrumbsProps extends React.HTMLAttributes<HTMLDivElement> {
4636
crumbs: Crumb[];
47-
48-
/**
49-
* As a general rule of thumb we don't want the last item to be link as it most likely
50-
* points to the same page we are currently on. This is by default false, so that
51-
* people don't have to check if crumb is last in the array and then manually
52-
* assign `to: null/undefined` when passing props to this component.
53-
*/
54-
linkLastItem?: boolean;
5537
}
5638

5739
/**
5840
* Page breadcrumbs used for navigation, not to be confused with sentry's event breadcrumbs
5941
*/
60-
export function Breadcrumbs({crumbs, linkLastItem = false, ...props}: Props) {
42+
export function Breadcrumbs({crumbs, ...props}: BreadcrumbsProps) {
6143
if (crumbs.length === 0) {
6244
return null;
6345
}
6446

65-
if (!linkLastItem) {
47+
if (crumbs[crumbs.length - 1]?.to) {
6648
crumbs[crumbs.length - 1]!.to = null;
6749
}
6850

6951
return (
70-
<BreadcrumbList {...props} data-test-id="breadcrumb-list">
52+
<Flex
53+
gap="xs"
54+
align="center"
55+
padding="md 0"
56+
{...props}
57+
data-test-id="breadcrumb-list"
58+
>
7159
{crumbs.map((crumb, index) => {
72-
const {label, to, preservePageFilters, key} = crumb;
73-
const labelKey = typeof label === 'string' ? label : '';
74-
const mapKey =
75-
key ?? (typeof to === 'string' ? `${labelKey}${to}` : `${labelKey}${index}`);
76-
7760
return (
78-
<Fragment key={mapKey}>
79-
{to ? (
80-
<BreadcrumbLink
81-
to={to}
82-
preservePageFilters={preservePageFilters}
83-
data-test-id="breadcrumb-link"
84-
>
85-
{label}
86-
</BreadcrumbLink>
87-
) : (
88-
<BreadcrumbItem data-test-id="breadcrumb-item">{label}</BreadcrumbItem>
89-
)}
90-
91-
{index < crumbs.length - 1 && <BreadcrumbDividerIcon direction="right" />}
61+
<Fragment key={index}>
62+
<BreadCrumbItem
63+
crumb={crumb}
64+
variant={index === crumbs.length - 1 ? 'primary' : 'muted'}
65+
/>
66+
{index < crumbs.length - 1 ? <BreadcumbChevron /> : null}
9267
</Fragment>
9368
);
9469
})}
95-
</BreadcrumbList>
70+
</Flex>
9671
);
9772
}
9873

99-
const getBreadcrumbListItemStyles = (p: {theme: Theme}) => css`
100-
${p.theme.overflowEllipsis}
101-
color: ${p.theme.subText};
102-
width: auto;
74+
interface BreadCrumbItemProps {
75+
crumb: Crumb;
76+
variant: 'primary' | 'muted';
77+
}
10378

104-
&:last-child {
105-
color: ${p.theme.textColor};
79+
function BreadCrumbItem(props: BreadCrumbItemProps) {
80+
if (props.crumb.to) {
81+
return (
82+
<BreadcrumbLink
83+
to={props.crumb.to}
84+
preservePageFilters={props.crumb.preservePageFilters}
85+
data-test-id="breadcrumb-link"
86+
>
87+
<Text as="span" variant="muted">
88+
{props.crumb.label}
89+
</Text>
90+
</BreadcrumbLink>
91+
);
10692
}
107-
`;
93+
return (
94+
<Flex data-test-id="breadcrumb-item" maxWidth="400px" align="center">
95+
<Text as="span" ellipsis variant={props.variant}>
96+
{props.crumb.label}
97+
</Text>
98+
</Flex>
99+
);
100+
}
108101

109102
interface BreadcrumbLinkProps {
110103
to: LinkProps['to'];
111104
children?: React.ReactNode;
112105
preservePageFilters?: boolean;
113106
}
114107

115-
const BreadcrumbLink = styled(
116-
({preservePageFilters, to, ...props}: BreadcrumbLinkProps) =>
117-
preservePageFilters ? (
118-
<GlobalSelectionLink to={to} {...props} />
119-
) : (
120-
<Link to={to} {...props} />
121-
)
122-
)`
123-
${getBreadcrumbListItemStyles}
124-
max-width: 400px;
125-
126-
&:hover,
127-
&:active {
128-
color: ${p => p.theme.subText};
108+
function BreadcrumbLink(props: BreadcrumbLinkProps) {
109+
if (props.preservePageFilters) {
110+
return <GlobalSelectionLink {...props} />;
129111
}
130-
`;
131-
132-
const BreadcrumbItem = styled('span')`
133-
${getBreadcrumbListItemStyles}
134-
max-width: 400px;
135-
`;
112+
return <Link {...props} />;
113+
}
136114

137-
const BreadcrumbDividerIcon = styled(Chevron)`
138-
color: ${p => p.theme.subText};
139-
margin: 0 ${space(0.5)};
140-
flex-shrink: 0;
141-
`;
115+
function BreadcumbChevron() {
116+
return (
117+
<Text variant="muted">
118+
<Flex flexShrink={0} align="center">
119+
<Chevron direction="right" color="subText" />
120+
</Flex>
121+
</Text>
122+
);
123+
}

0 commit comments

Comments
 (0)