Skip to content

Commit

Permalink
Merge pull request Expensify#32221 from software-mansion-labs/wave8/b…
Browse files Browse the repository at this point in the history
…readcrumbs

[NoQA] [Wave8] Breadcrumbs
  • Loading branch information
mountiny authored Dec 18, 2023
2 parents 648c000 + 0d30c94 commit c96a209
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 6 deletions.
6 changes: 6 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ const CONST = {
AVATAR_MAX_WIDTH_PX: 4096,
AVATAR_MAX_HEIGHT_PX: 4096,

BREADCRUMB_TYPE: {
ROOT: 'root',
STRONG: 'strong',
NORMAL: 'normal',
},

DEFAULT_AVATAR_COUNT: 24,
OLD_DEFAULT_AVATAR_COUNT: 8,

Expand Down
80 changes: 80 additions & 0 deletions src/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import {StyleProp, View, ViewStyle} from 'react-native';
import LogoComponent from '@assets/images/expensify-wordmark.svg';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import Header from './Header';
import Text from './Text';

type BreadcrumbHeader = {
type: typeof CONST.BREADCRUMB_TYPE.ROOT;
};

type BreadcrumbStrong = {
text: string;
type: typeof CONST.BREADCRUMB_TYPE.STRONG;
};

type Breadcrumb = {
text: string;
type?: typeof CONST.BREADCRUMB_TYPE.NORMAL;
};

type BreadcrumbsProps = {
/** An array of breadcrumbs consisting of the root/strong breadcrumb, followed by an optional second level breadcrumb */
breadcrumbs: [BreadcrumbHeader | BreadcrumbStrong, Breadcrumb | undefined];

/** Styles to apply to the container */
style?: StyleProp<ViewStyle>;
};

function Breadcrumbs({breadcrumbs, style}: BreadcrumbsProps) {
const theme = useTheme();
const styles = useThemeStyles();
const [primaryBreadcrumb, secondaryBreadcrumb] = breadcrumbs;

return (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.gap1, styles.w100, style]}>
{primaryBreadcrumb.type === CONST.BREADCRUMB_TYPE.ROOT ? (
<View style={styles.breadcrumbLogo}>
<Header
title={
<LogoComponent
fill={theme.text}
width={variables.lhnLogoWidth}
height={variables.lhnLogoHeight}
/>
}
shouldShowEnvironmentBadge
/>
</View>
) : (
<Text
numberOfLines={1}
style={[styles.flexShrink1, styles.breadcrumb, styles.breadcrumbStrong]}
>
{primaryBreadcrumb.text}
</Text>
)}

{!!secondaryBreadcrumb && (
<>
<Text style={[styles.breadcrumbSeparator]}>/</Text>
<Text
numberOfLines={1}
style={[styles.mw75, styles.flexShrink0, styles.breadcrumb]}
>
{secondaryBreadcrumb.text}
</Text>
</>
)}
</View>
);
}

Breadcrumbs.displayName = 'Breadcrumbs';

export type {BreadcrumbsProps};
export default Breadcrumbs;
2 changes: 1 addition & 1 deletion src/components/EnvironmentBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function EnvironmentBadge() {
success={environment === CONST.ENVIRONMENT.STAGING || environment === CONST.ENVIRONMENT.ADHOC}
error={environment !== CONST.ENVIRONMENT.STAGING && environment !== CONST.ENVIRONMENT.ADHOC}
text={text}
badgeStyles={[styles.alignSelfEnd, styles.headerEnvBadge]}
badgeStyles={[styles.alignSelfStart, styles.headerEnvBadge]}
textStyles={[styles.headerEnvBadgeText]}
environment={environment}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/TeachersUnite/ImTeacherUpdateEmailPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function ImTeacherUpdateEmailPage() {
linkKey="teachersUnitePage.contactMethods"
onLinkPress={() => Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(activeRoute))}
iconWidth={variables.signInLogoWidthLargeScreen}
iconHeight={variables.lhnLogoWidth}
iconHeight={variables.signInLogoHeightLargeScreen}
/>
<FixedFooter style={[styles.flexGrow0]}>
<Button
Expand Down
50 changes: 50 additions & 0 deletions src/stories/Breadcrumbs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import Breadcrumbs, {BreadcrumbsProps} from '@components/Breadcrumbs';
import CONST from '@src/CONST';

/**
* We use the Component Story Format for writing stories. Follow the docs here:
*
* https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
*/
const story = {
title: 'Components/Breadcrumbs',
component: Breadcrumbs,
};

type StoryType = typeof Template & {args?: Partial<BreadcrumbsProps>};

function Template(args: BreadcrumbsProps) {
// eslint-disable-next-line react/jsx-props-no-spreading
return <Breadcrumbs {...args} />;
}

// Arguments can be passed to the component by binding
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Default: StoryType = Template.bind({});
Default.args = {
breadcrumbs: [
{
type: CONST.BREADCRUMB_TYPE.ROOT,
},
{
text: 'Chats',
},
],
};

const FirstBreadcrumbStrong: StoryType = Template.bind({});
FirstBreadcrumbStrong.args = {
breadcrumbs: [
{
text: "Cathy's Croissants",
type: CONST.BREADCRUMB_TYPE.STRONG,
},
{
text: 'Chats',
},
],
};

export default story;
export {Default, FirstBreadcrumbStrong};
33 changes: 31 additions & 2 deletions src/styles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,31 @@ const styles = (theme: ThemeColors) =>
justifyContent: 'center',
textDecorationLine: 'none',
},

breadcrumb: {
color: theme.textSupporting,
fontSize: variables.fontSizeh1,
lineHeight: variables.lineHeightSizeh1,
...headlineFont,
},

breadcrumbStrong: {
color: theme.text,
fontSize: variables.fontSizeXLarge,
},

breadcrumbSeparator: {
color: theme.icon,
fontSize: variables.fontSizeXLarge,
lineHeight: variables.lineHeightSizeh1,
...headlineFont,
},

breadcrumbLogo: {
top: 1.66, // Pixel-perfect alignment due to a small difference between logo height and breadcrumb text height
height: variables.lineHeightSizeh1,
},

LHPNavigatorContainer: (isSmallScreenWidth: boolean) =>
({
width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,
Expand All @@ -1389,6 +1414,7 @@ const styles = (theme: ThemeColors) =>
borderBottomRightRadius: isSmallScreenWidth ? 0 : 24,
overflow: 'hidden',
} satisfies ViewStyle),

RHPNavigatorContainer: (isSmallScreenWidth: boolean) =>
({
width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,
Expand Down Expand Up @@ -3567,12 +3593,15 @@ const styles = (theme: ThemeColors) =>
},

headerEnvBadge: {
marginLeft: 0,
marginBottom: 2,
position: 'absolute',
bottom: -8,
left: -8,
height: 12,
width: 22,
paddingLeft: 4,
paddingRight: 4,
alignItems: 'center',
zIndex: -1,
},

headerEnvBadgeText: {
Expand Down
4 changes: 4 additions & 0 deletions src/styles/utils/sizing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export default {
maxWidth: 'auto',
},

mw75: {
maxWidth: '75%',
},

mw100: {
maxWidth: '100%',
},
Expand Down
5 changes: 3 additions & 2 deletions src/styles/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,12 @@ export default {
signInLogoHeight: 34,
signInLogoWidth: 120,
signInLogoWidthLargeScreen: 144,
signInLogoHeightLargeScreen: 108,
signInLogoWidthPill: 132,
tabSelectorButtonHeight: 40,
tabSelectorButtonPadding: 12,
lhnLogoWidth: 108,
lhnLogoHeight: 28,
lhnLogoWidth: 95.09,
lhnLogoHeight: 22.33,
signInLogoWidthLargeScreenPill: 162,
modalContentMaxWidth: 360,
listItemHeightNormal: 64,
Expand Down

0 comments on commit c96a209

Please sign in to comment.