Skip to content

Commit

Permalink
feat(Timeline): migrate to tailwind
Browse files Browse the repository at this point in the history
  • Loading branch information
vbulant authored and DSil committed Mar 13, 2024
1 parent 3b6617b commit 6fdc700
Show file tree
Hide file tree
Showing 41 changed files with 275 additions and 233 deletions.
4 changes: 2 additions & 2 deletions docs/src/data/tailwind-migration-status.yaml
Expand Up @@ -106,8 +106,8 @@ TextOrbit: true
Text: true
TextLink: true
Textarea: true
Timeline: false
TimelineStep: false
Timeline: true
TimelineStep: true
Toast: true
ToastRoot: true
Tooltip: true
Expand Down
2 changes: 1 addition & 1 deletion packages/orbit-components/playwright/index.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Expand Down
69 changes: 69 additions & 0 deletions packages/orbit-components/src/Timeline/Timeline.ct-story.tsx
@@ -0,0 +1,69 @@
import * as React from "react";

import SPACINGS_AFTER from "../common/getSpacingToken/consts";

import Timeline, { TimelineStep } from ".";

const DIRECTIONS = ["row", "column"] as const;
const TYPES = ["success", "warning", "critical", "info", undefined] as const;

export default function TimelineStory() {
return (
<div className="p-md">
{Object.values(SPACINGS_AFTER).map(spaceAfter => (
<Timeline spaceAfter={spaceAfter}>
<TimelineStep label="Only one step" />
</Timeline>
))}

{DIRECTIONS.map(direction => (
<>
<Timeline direction={direction}>
<TimelineStep label="Requested" subLabel="3rd May 14:04" />
<TimelineStep
label="In progress (this is quite a long sentence just to see how it plays out)"
subLabel="4th May 10:25 (this is quite a long sentence just to see how it plays out)"
/>
<TimelineStep label="Refunded">
We’ll forward you all refunds from the carrier(s) after we receive it.
</TimelineStep>
</Timeline>

<Timeline direction={direction}>
<TimelineStep type="success" label="Requested" subLabel="3rd May 14:04">
We’ve received your request and will assign it to one of our agents.
</TimelineStep>
<TimelineStep active type="warning" label="In progress" subLabel="4th May 10:25">
We’ll review your request and apply for any available refund from the carrier(s)
</TimelineStep>
<TimelineStep type="critical" label="Waiting for the carrier" subLabel="5th May 14:04">
We’ll wait for the carrier(s) to send us the refund and contact them again if
necessary.
</TimelineStep>
<TimelineStep type="info" label="Carrier is refunding" subLabel="6th May 14:04">
The carrier has sent us a refund. There might be more depending on their policy.
</TimelineStep>
<TimelineStep label="Refunded" subLabel="7th May 10:25">
We’ll forward you all refunds from the carrier(s) after we receive it.
</TimelineStep>
</Timeline>

<Timeline direction={direction}>
{TYPES.map(type => (
<TimelineStep type={type} label="Yay" />
))}
</Timeline>

<Timeline direction={direction}>
<TimelineStep label="Label only" />
<TimelineStep label="Label" subLabel="Sublabel" />
<TimelineStep label="Label">Children</TimelineStep>
<TimelineStep label="Label" subLabel="Sublabel">
Children
</TimelineStep>
</Timeline>
</>
))}
</div>
);
}
23 changes: 23 additions & 0 deletions packages/orbit-components/src/Timeline/Timeline.ct.tsx
@@ -0,0 +1,23 @@
import * as React from "react";
import { test, expect } from "@playwright/experimental-ct-react";

import TimelineStory from "./Timeline.ct-story";
import RenderInRtl from "../utils/rtl/RenderInRtl";

test.describe("visual Timeline", () => {
test("default", async ({ mount }) => {
const component = await mount(<TimelineStory />);

await expect(component).toHaveScreenshot();
});

test("rtl", async ({ mount }) => {
const component = await mount(
<RenderInRtl>
<TimelineStory />
</RenderInRtl>,
);

await expect(component).toHaveScreenshot();
});
});
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,72 @@
import * as React from "react";
import cx from "clsx";

import type { Type } from "../types";
import useTheme from "../../../hooks/useTheme";
import type { Theme } from "../../../defaultTheme";

export const getStatusColor = (theme: Theme, type?: Type): string => {
const colors = {
success: theme.orbit.colorTextSuccess,
warning: theme.orbit.colorTextWarning,
critical: theme.orbit.colorTextCritical,
info: theme.orbit.colorTextInfo,
};

return type ? colors[type] : theme.orbit.paletteCloudNormalHover;
};

interface Props {
desktop?: boolean;
last?: boolean;
nextStatus?: Type;
prevStatus?: Type;
status?: Type;
}

const ProgressLine = ({ desktop, status, nextStatus, last, prevStatus }: Props) => {
const theme = useTheme();

const getBorderStyle = (): React.CSSProperties => {
if (desktop) {
if (status && !nextStatus && !last) {
return {
borderImageSlice: 1,
borderImageSource: `linear-gradient(to right, ${getStatusColor(
theme,
prevStatus,
)}, ${getStatusColor(theme, status)})`,
};
}
}

if (status && !nextStatus && !last) {
return {
borderImageSlice: 1,
borderImageSource: `linear-gradient(to bottom, ${getStatusColor(
theme,
prevStatus,
)}, ${getStatusColor(theme, status)})`,
};
}

return {
borderColor: getStatusColor(theme, status),
};
};

return (
<span
className={cx(
"border",
status ? "border-solid" : "border-dashed",
desktop
? "w-1/2"
: "absolute top-[15px] h-[calc(100%+theme(spacing.xxxs))] ltr:left-[11px] rtl:right-[11px]",
)}
style={getBorderStyle()}
/>
);
};

export default ProgressLine;
@@ -0,0 +1,16 @@
import * as React from "react";
import cx from "clsx";

type Props = React.PropsWithChildren<{
active?: boolean;
}>;

const TextWrapper = ({ active, children }: Props) => {
return (
<div className={cx("de:min-h-md", active ? "[&>p]:text-ink-dark" : "[&>p]:text-ink-light")}>
{children}
</div>
);
};

export default TextWrapper;
@@ -1,30 +1,14 @@
import * as React from "react";
import styled, { css } from "styled-components";
import cx from "clsx";

import StyledRelative from "../primitives/StyledRelative";
import TypeIcon from "./TypeIcon";
import StyledProgressLine from "../primitives/StyledProgressLine";
import StyledText from "../primitives/StyledText";
import ProgressLine from "./ProgressLine";
import TextWrapper from "./TextWrapper";
import Text from "../../../Text";
import Stack from "../../../Stack";
import defaultTheme from "../../../defaultTheme";
import type { Props as StepProps, Type } from "../types";
import useTheme from "../../../hooks/useTheme";

const StyledDescription = styled.div<{ active?: boolean }>`
${({ theme, active }) => css`
max-width: 250px;
width: 100%;
> p {
color: ${active ? theme.orbit.paletteInkDark : theme.orbit.paletteInkLight};
}
`}
`;

StyledDescription.defaultProps = {
theme: defaultTheme,
};

interface Props extends StepProps {
last: boolean;
prevType: Type;
Expand All @@ -47,38 +31,45 @@ const TimelineStepDesktop = ({

return (
<Stack inline shrink direction="column" align="center">
<StyledRelative inner>
<StyledProgressLine desktop status={type} prevStatus={prevType} nextStatus={nextType} />
<div className={cx("relative flex w-[calc(100%+theme(spacing.md))] items-center")}>
<ProgressLine desktop status={type} prevStatus={prevType} nextStatus={nextType} />
<TypeIcon type={type} active={!!active} />
<StyledProgressLine
<ProgressLine
desktop
status={!nextType && !last ? undefined : type}
prevStatus={prevType}
nextStatus={nextType}
last={last}
/>
</StyledRelative>
</div>
<Stack flex align="center" spacing="XSmall" direction="column">
{subLabel && (
<StyledText>
<TextWrapper>
<Text align="center" size="small">
{subLabel}
</Text>
</StyledText>
</TextWrapper>
)}
<StyledText active={active || (last && type === "success")}>
<TextWrapper active={active || (last && type === "success")}>
<Text
align="center"
weight="bold"
margin={{ top: !subLabel && hasSubLabelMargin ? theme.orbit.spaceLarge : 0 }}
>
{label}
</Text>
</StyledText>
</TextWrapper>
{children && (
<StyledDescription active={active || (last && type === "success")}>
<div
className={cx(
"w-full max-w-[250px]",
active || (last && type === "success")
? "[&>p]:text-ink-dark"
: "[&>p]:text-ink-light",
)}
>
<Text align="center">{children}</Text>
</StyledDescription>
</div>
)}
</Stack>
</Stack>
Expand Down
@@ -1,11 +1,10 @@
import * as React from "react";

import StyledRelative from "../primitives/StyledRelative";
import Text from "../../../Text";
import Stack from "../../../Stack";
import StyledProgressLine from "../primitives/StyledProgressLine";
import ProgressLine from "./ProgressLine";
import TypeIcon from "./TypeIcon";
import StyledText from "../primitives/StyledText";
import TextWrapper from "./TextWrapper";
import type { Props as StepProps, Type } from "../types";

interface Props extends StepProps {
Expand All @@ -15,34 +14,34 @@ interface Props extends StepProps {

const TimelineStepMobile = ({ type, subLabel, label, nextType, children, active, last }: Props) => {
return (
<StyledRelative>
<div className="relative">
<Stack
flex
spaceAfter={last ? undefined : "large"}
align="stretch"
desktop={{ align: "start" }}
>
<TypeIcon type={type} active={!!active} mobile />
{!last && <StyledProgressLine status={nextType} prevStatus={type} />}
{!last && <ProgressLine status={nextType} prevStatus={type} />}
<Stack flex shrink direction="column" spacing="XXSmall">
<Stack flex direction="column" spacing="XXSmall">
<StyledText active={active || (last && type === "success")}>
<TextWrapper active={active || (last && type === "success")}>
<Text weight="bold">{label}</Text>
</StyledText>
</TextWrapper>
{subLabel && (
<StyledText active={active}>
<TextWrapper active={active}>
<Text size="small">{subLabel}</Text>
</StyledText>
</TextWrapper>
)}
</Stack>
{children && (
<StyledText active={active || (last && type === "success")}>
<TextWrapper active={active || (last && type === "success")}>
<Text>{children}</Text>
</StyledText>
</TextWrapper>
)}
</Stack>
</Stack>
</StyledRelative>
</div>
);
};

Expand Down

0 comments on commit 6fdc700

Please sign in to comment.