implemented popover for annotate

This commit is contained in:
Sebastian Sdorra
2020-06-12 11:29:23 +02:00
parent 9c5e0c64fd
commit 24444aa065
5 changed files with 110 additions and 14 deletions

View File

@@ -26,6 +26,8 @@ import { storiesOf } from "@storybook/react";
import * as React from "react";
import styled from "styled-components";
import Annotate, { AnnotatedSource } from "./Annotate";
import { MemoryRouter } from "react-router-dom";
import repository from "./__resources__/repository";
const Wrapper = styled.div`
margin: 2rem;
@@ -108,5 +110,6 @@ const source: AnnotatedSource = {
};
storiesOf("Annotate", module)
.addDecorator(storyFn => <Wrapper className="box box-link-shadow">{storyFn()}</Wrapper>)
.add("Default", () => <Annotate source={source} />);
.addDecorator(storyFn => <MemoryRouter initialEntries={["/"]}>{storyFn()}</MemoryRouter>)
.addDecorator(storyFn => <Wrapper className="box">{storyFn()}</Wrapper>)
.add("Default", () => <Annotate source={source} repository={repository} />);

View File

@@ -23,7 +23,7 @@
*/
import React, { FC } from "react";
import { Person } from "@scm-manager/ui-types";
import { Person, Repository } from "@scm-manager/ui-types";
// @ts-ignore
import { LightAsync as ReactSyntaxHighlighter, createElement } from "react-syntax-highlighter";
@@ -32,6 +32,9 @@ import { LightAsync as ReactSyntaxHighlighter, createElement } from "react-synta
import { arduinoLight } from "react-syntax-highlighter/dist/cjs/styles/hljs";
import styled from "styled-components";
import DateShort from "./DateShort";
import { SingleContributor } from "./repos/changesets";
import DateFromNow from "./DateFromNow";
import { Link } from "react-router-dom";
// TODO move types to ui-types
@@ -51,13 +54,14 @@ export type AnnotatedLine = {
type Props = {
source: AnnotatedSource;
repository: Repository;
};
type LineElementProps = {
newAnnotation: boolean;
};
const Author = styled.a<LineElementProps>`
const Author = styled.span<LineElementProps>`
width: 8em;
overflow: hidden;
text-overflow: ellipsis;
@@ -93,7 +97,72 @@ const LineNumber = styled.span`
padding: 0 0.5em;
`;
const Annotate: FC<Props> = ({ source }) => {
const Popover = styled.div`
position: absolute;
left: -16.5em;
bottom: 0.1em;
z-index: 100;
visibility: hidden;
overflow: visible;
width: 35em;
&:before {
position: absolute;
content: "";
border-style: solid;
pointer-events: none;
height: 0;
width: 0;
top: 100%;
/*left: 50%;*/
border-color: transparent;
border-bottom-color: white;
border-left-color: white;
border-width: 0.4rem;
margin-left: -0.4rem;
margin-top: -0.4rem;
-webkit-transform-origin: center;
transform-origin: center;
box-shadow: -1px 1px 2px rgba(10, 10, 10, 0.2);
transform: rotate(-45deg);
}
`;
const Line = styled.span`
position: relative;
z-index: 10;
&:hover .changeset-details {
visibility: visible !important;
}
`;
const PreTag = styled.pre`
overflow-x: visible !important;
`;
const SmallHr = styled.hr`
margin: 0.5em 0;
`;
const PopoverHeading = styled.div`
height: 1.5em;
`;
const PopoverDescription = styled.p`
margin-top: 0.5em;
`;
const shortRevision = (revision: string) => {
if (revision.length > 7) {
return revision.substring(0, 7);
}
return revision;
};
const Annotate: FC<Props> = ({ source, repository }) => {
// @ts-ignore
const defaultRenderer = ({ rows, stylesheet, useInlineStyles }) => {
let lastRevision = "";
@@ -111,13 +180,26 @@ const Annotate: FC<Props> = ({ source }) => {
const newAnnotation = annotation.revision !== lastRevision;
lastRevision = annotation.revision;
return (
<span>
<Author newAnnotation={newAnnotation}>{annotation.author.name}</Author>{" "}
<Line>
<Popover className="box changeset-details is-family-primary">
<PopoverHeading className="is-clearfix">
<SingleContributor className="is-pulled-left" person={annotation.author} />
<DateFromNow className="is-pulled-right" date={annotation.when} />
</PopoverHeading>
<SmallHr />
<p className="has-text-info">Changeset {shortRevision(annotation.revision)}</p>
<PopoverDescription className="content">{annotation.description}</PopoverDescription>
</Popover>
<Author className="trigger" newAnnotation={newAnnotation}>
<Link to={`/repo/${repository.namespace}/${repository.name}/code/changeset/${annotation.revision}`}>
{annotation.author.name}
</Link>
</Author>{" "}
<When newAnnotation={newAnnotation}>
<DateShort value={annotation.when} />
</When>{" "}
<LineNumber>{i + 1}</LineNumber> {line}
</span>
</Line>
);
}
@@ -136,6 +218,7 @@ const Annotate: FC<Props> = ({ source }) => {
language={source.language}
style={arduinoLight}
renderer={defaultRenderer}
PreTag={PreTag}
>
{code}
</ReactSyntaxHighlighter>

View File

@@ -49,6 +49,7 @@ type Props = WithTranslation & {
* ci server.
*/
baseDate?: DateInput;
className?: string;
};
type Options = {
@@ -100,13 +101,17 @@ class DateFromNow extends React.Component<Props> {
};
render() {
const { date } = this.props;
const { date, className } = this.props;
if (date) {
const isoDate = toDate(date);
const options = this.createOptions();
const distance = formatDistance(isoDate, this.getBaseDate(), options);
const formatted = format(isoDate, FullDateFormat, options);
return <DateElement title={formatted}>{distance}</DateElement>;
return (
<DateElement className={className} title={formatted}>
{distance}
</DateElement>
);
}
return null;
}

View File

@@ -36,6 +36,7 @@ type Props = {
type PersonProps = {
person: Person;
className?: string;
displayTextOnly?: boolean;
};
@@ -70,7 +71,7 @@ const ContributorWithAvatar: FC<PersonAvatarProps> = ({ person, avatar }) => {
return <ContributorAvatar src={avatar} alt={person.name} title={person.name} />;
};
const SingleContributor: FC<PersonProps> = ({ person, displayTextOnly }) => {
export const SingleContributor: FC<PersonProps> = ({ person, className, displayTextOnly }) => {
const [t] = useTranslation("repos");
const avatar = useAvatar(person);
if (!displayTextOnly && avatar) {
@@ -78,12 +79,16 @@ const SingleContributor: FC<PersonProps> = ({ person, displayTextOnly }) => {
}
if (person.mail) {
return (
<a href={"mailto:" + person.mail} title={t("changeset.contributors.mailto") + " " + person.mail}>
<a
className={className}
href={"mailto:" + person.mail}
title={t("changeset.contributors.mailto") + " " + person.mail}
>
{person.name}
</a>
);
}
return <>{person.name}</>;
return <span className={className}>{person.name}</span>;
};
type PersonsProps = {

View File

@@ -25,7 +25,7 @@
import * as changesets from "./changesets";
export { changesets };
export { default as ChangesetAuthor } from "./ChangesetAuthor";
export { default as ChangesetAuthor, SingleContributor } from "./ChangesetAuthor";
export { default as ChangesetButtonGroup } from "./ChangesetButtonGroup";
export { default as ChangesetDiff } from "./ChangesetDiff";
export { default as ChangesetId } from "./ChangesetId";