mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-09 06:55:47 +01:00
implemented popover for annotate
This commit is contained in:
@@ -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} />);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user