Skip to content
Snippets Groups Projects
Unverified Commit 85360241 authored by Dalton's avatar Dalton Committed by GitHub
Browse files

add timeline component (#15777)

* add timeline component

* rmv BEM classes
parent a88351d7
Branches
Tags
No related merge requests found
import React from "react";
import moment from "moment";
import styled from "styled-components";
import Timeline from "metabase/components/Timeline";
import { color } from "metabase/lib/colors";
export const component = Timeline;
export const category = "display";
export const description = `
A component for showing events in descending order.
`;
const Container = styled.div`
line-height: 1.5;
width: 350px;
border: 1px dashed ${color("bg-dark")};
border-radius: 0.5rem;
padding: 1rem;
`;
const items = [
{
icon: "verified",
title: "John Someone verified this",
description: "idk lol",
timestamp: moment()
.subtract(1, "day")
.valueOf(),
numComments: 5,
},
{
icon: "pencil",
title: "Foo edited this",
description: "Did a thing.",
timestamp: moment()
.subtract(1, "week")
.valueOf(),
},
{
icon: "warning_colorized",
title: "Someone McSomeone thinks something looks wrong",
description:
"Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. \nUh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not correct. Uh oh that's not",
timestamp: moment()
.subtract(2, "month")
.valueOf(),
},
{
icon: "clarification",
title: "Someone is confused",
description:
"Something something something something something something something something something something something something?",
timestamp: moment()
.subtract(1, "year")
.valueOf(),
numComments: 123,
},
];
function renderFooter(item) {
return item.numComments ? (
<a
href="/_internal/components/timeline"
className="text-underline"
>{`${item.numComments} comments`}</a>
) : (
""
);
}
export const examples = {
"Constrained width": (
<Container>
<Timeline items={items} />
</Container>
),
"Optional footer": <Timeline items={items} renderFooter={renderFooter} />,
};
import React, { useMemo } from "react";
import PropTypes from "prop-types";
import _ from "underscore";
import styled from "styled-components";
import moment from "moment";
import { color } from "metabase/lib/colors";
import Icon from "metabase/components/Icon";
const TimelineContainer = styled.div`
position: relative;
margin-left: ${props => props.leftShift}px;
margin-bottom: ${props => props.bottomShift}px;
`;
const TimelineItem = styled.div`
transform: translateX(-${props => props.leftShift}px);
white-space: pre-line;
`;
// shift the border down slightly so that it doesn't appear above the top-most icon
const Border = styled.div`
position: absolute;
top: ${props => props.borderShift}px;
left: 0;
right: 0;
bottom: -${props => props.borderShift}px;
border-left: 1px solid ${color("border")};
`;
const Timeline = ({ className, items = [], renderFooter }) => {
const iconSize = 20;
const halfIconSize = iconSize / 2;
const sortedFormattedItems = useMemo(() => {
return items
.sort((a, b) => b.timestamp - a.timestamp)
.map(item => {
return {
...item,
formattedTimestamp: moment(item.timestamp).fromNow(),
};
});
}, [items]);
return (
<TimelineContainer
leftShift={halfIconSize}
bottomShift={halfIconSize}
className={className}
>
<Border borderShift={halfIconSize} />
{sortedFormattedItems.map((item, index) => {
const { icon, title, description, formattedTimestamp } = item;
const key = item.key == null ? index : item.key;
return (
<TimelineItem
key={key}
leftShift={halfIconSize}
className="flex align-start justify-start mb2"
>
<Icon className="text-light" name={icon} size={iconSize} />
<div className="ml1">
<div className="text-bold">{title}</div>
<div className="text-medium text-small">{formattedTimestamp}</div>
<div>{description}</div>
{_.isFunction(renderFooter) && <div>{renderFooter(item)}</div>}
</div>
</TimelineItem>
);
})}
</TimelineContainer>
);
};
Timeline.propTypes = {
className: PropTypes.string,
items: PropTypes.array,
renderFooter: PropTypes.func,
};
export default Timeline;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment