@scm-manager/ui-components 4.0.0-REACT19-20250928-144148 → 4.0.0-REACT19-20251020-110745
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/src/CardColumn.stories.tsx +2 -2
- package/src/Duration.stories.tsx +1 -1
- package/src/__snapshots__/storyshots.test.ts.snap +1 -1
- package/src/index.ts +0 -3
- package/src/repos/RepositoryEntry.stories.tsx +3 -4
- package/src/repos/RepositoryEntry.tsx +3 -10
- package/src/repos/annotate/Annotate.stories.tsx +0 -2
- package/src/repos/annotate/Annotate.tsx +1 -4
- package/src/repos/annotate/AnnotateLine.tsx +1 -1
- package/src/repos/annotate/AnnotatePopover.tsx +3 -5
- package/src/repos/changesets/SingleChangeset.tsx +1 -1
- package/src/Date.stories.tsx +0 -99
- package/src/DateElement.ts +0 -24
- package/src/DateFromNow.tsx +0 -39
- package/src/DateShort.tsx +0 -39
- package/src/useDateFormatter.test.ts +0 -39
- package/src/useDateFormatter.ts +0 -118
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scm-manager/ui-components",
|
|
3
|
-
"version": "4.0.0-REACT19-
|
|
3
|
+
"version": "4.0.0-REACT19-20251020-110745",
|
|
4
4
|
"description": "UI Components for SCM-Manager and its plugins",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"files": [
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"@scm-manager/eslint-config": "^2.18.2",
|
|
37
37
|
"@scm-manager/prettier-config": "^2.12.0",
|
|
38
38
|
"@scm-manager/tsconfig": "^2.13.0",
|
|
39
|
-
"@scm-manager/ui-syntaxhighlighting": "4.0.0-REACT19-
|
|
40
|
-
"@scm-manager/ui-types": "4.0.0-REACT19-
|
|
39
|
+
"@scm-manager/ui-syntaxhighlighting": "4.0.0-REACT19-20251020-110745",
|
|
40
|
+
"@scm-manager/ui-types": "4.0.0-REACT19-20251020-110745",
|
|
41
41
|
"@storybook/addon-actions": "^9.0.8",
|
|
42
42
|
"@storybook/addon-docs": "^9.1.5",
|
|
43
43
|
"@storybook/addon-essentials": "^9.0.0-alpha.12",
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"vitest": "^3.2.4"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@scm-manager/ui-api": "4.0.0-REACT19-
|
|
72
|
-
"@scm-manager/ui-core": "4.0.0-REACT19-
|
|
73
|
-
"@scm-manager/ui-extensions": "4.0.0-REACT19-
|
|
71
|
+
"@scm-manager/ui-api": "4.0.0-REACT19-20251020-110745",
|
|
72
|
+
"@scm-manager/ui-core": "4.0.0-REACT19-20251020-110745",
|
|
73
|
+
"@scm-manager/ui-extensions": "4.0.0-REACT19-20251020-110745",
|
|
74
74
|
"deepmerge": "^4.2.2",
|
|
75
75
|
"hast-util-sanitize": "^3.0.2",
|
|
76
76
|
"react-diff-view": "2.6.0",
|
|
@@ -68,7 +68,7 @@ import type { Meta, StoryObj } from "@storybook/react";
|
|
|
68
68
|
|
|
69
69
|
import CardColumn from "./CardColumn";
|
|
70
70
|
import Icon from "./Icon";
|
|
71
|
-
import { DateFromNow } from "
|
|
71
|
+
import { DateFromNow } from "@scm-manager/ui-core";
|
|
72
72
|
import repository from "./__resources__/repository";
|
|
73
73
|
|
|
74
74
|
const Wrapper = styled.div`
|
|
@@ -122,7 +122,7 @@ export const WithHoverableDate: Story = {
|
|
|
122
122
|
footerLeft: footerLeft,
|
|
123
123
|
footerRight: (
|
|
124
124
|
<small className="level-item">
|
|
125
|
-
<DateFromNow
|
|
125
|
+
<DateFromNow date={repository.creationDate} />
|
|
126
126
|
</small>
|
|
127
127
|
),
|
|
128
128
|
},
|
package/src/Duration.stories.tsx
CHANGED
package/src/index.ts
CHANGED
|
@@ -34,9 +34,6 @@ import {
|
|
|
34
34
|
|
|
35
35
|
export { validation, repositories };
|
|
36
36
|
|
|
37
|
-
export { default as DateFromNow } from "./DateFromNow";
|
|
38
|
-
export { default as DateShort } from "./DateShort";
|
|
39
|
-
export { default as useDateFormatter } from "./useDateFormatter";
|
|
40
37
|
export { default as Duration } from "./Duration";
|
|
41
38
|
export { default as ErrorNotification } from "./ErrorNotification";
|
|
42
39
|
export { default as ErrorPage } from "./ErrorPage";
|
|
@@ -181,7 +181,7 @@ const bindBeforeTitle = (binder: Binder, extension: ReactNode) => {
|
|
|
181
181
|
|
|
182
182
|
const withBinder = (binder: Binder, repo: Repository) => (
|
|
183
183
|
<BinderContext.Provider value={binder}>
|
|
184
|
-
<RepositoryEntry repository={repo}
|
|
184
|
+
<RepositoryEntry repository={repo} />
|
|
185
185
|
</BinderContext.Provider>
|
|
186
186
|
);
|
|
187
187
|
|
|
@@ -215,7 +215,8 @@ const meta: Meta<typeof RepositoryEntry> = {
|
|
|
215
215
|
component: RepositoryEntry,
|
|
216
216
|
decorators: [
|
|
217
217
|
(Story) => <MemoryRouter initialEntries={["/"]}>{Story()}</MemoryRouter>,
|
|
218
|
-
(Story) => <Container>{Story()}</Container
|
|
218
|
+
(Story) => <Container>{Story()}</Container>,
|
|
219
|
+
],
|
|
219
220
|
tags: ["autodocs"],
|
|
220
221
|
};
|
|
221
222
|
|
|
@@ -226,7 +227,6 @@ type Story = StoryObj<typeof meta>;
|
|
|
226
227
|
export const Default: Story = {
|
|
227
228
|
args: {
|
|
228
229
|
repository: repository,
|
|
229
|
-
baseDate: baseDate,
|
|
230
230
|
},
|
|
231
231
|
};
|
|
232
232
|
|
|
@@ -234,7 +234,6 @@ export const WithLongTexts: Story = {
|
|
|
234
234
|
name: "With Long Texts",
|
|
235
235
|
args: {
|
|
236
236
|
repository: longTextRepository,
|
|
237
|
-
baseDate: baseDate,
|
|
238
237
|
},
|
|
239
238
|
};
|
|
240
239
|
|
|
@@ -18,20 +18,14 @@ import React, { FC } from "react";
|
|
|
18
18
|
import { useTranslation } from "react-i18next";
|
|
19
19
|
import { Link } from "react-router-dom";
|
|
20
20
|
import styled from "styled-components";
|
|
21
|
-
import { Card, Icon, Menu, useKeyboardIteratorTargetV2 } from "@scm-manager/ui-core";
|
|
21
|
+
import { Card, Icon, Menu, useKeyboardIteratorTargetV2, DateFromNow } from "@scm-manager/ui-core";
|
|
22
22
|
import { ExtensionPoint, extensionPoints } from "@scm-manager/ui-extensions";
|
|
23
23
|
import { Repository } from "@scm-manager/ui-types";
|
|
24
|
-
import DateFromNow from "../DateFromNow";
|
|
25
24
|
import RepositoryAvatar from "./RepositoryAvatar";
|
|
26
25
|
import RepositoryFlags from "./RepositoryFlags";
|
|
27
26
|
|
|
28
|
-
type DateProp = Date | string;
|
|
29
|
-
|
|
30
27
|
type Props = {
|
|
31
28
|
repository: Repository;
|
|
32
|
-
// @VisibleForTesting
|
|
33
|
-
// the baseDate is only to avoid failing snapshot tests
|
|
34
|
-
baseDate?: DateProp;
|
|
35
29
|
expectedIndex?: number;
|
|
36
30
|
};
|
|
37
31
|
|
|
@@ -57,7 +51,7 @@ const DetailsRow = styled(Card.Row)`
|
|
|
57
51
|
gap: 0.5rem;
|
|
58
52
|
`;
|
|
59
53
|
|
|
60
|
-
const RepositoryEntry: FC<Props> = ({ repository,
|
|
54
|
+
const RepositoryEntry: FC<Props> = ({ repository, expectedIndex }) => {
|
|
61
55
|
const [t] = useTranslation("repos");
|
|
62
56
|
const ref = useKeyboardIteratorTargetV2({ expectedIndex: expectedIndex ?? 0 });
|
|
63
57
|
|
|
@@ -120,8 +114,7 @@ const RepositoryEntry: FC<Props> = ({ repository, baseDate, expectedIndex }) =>
|
|
|
120
114
|
<DescriptionRow className="is-size-7">{repository.description}</DescriptionRow>
|
|
121
115
|
<DetailsRow className="is-flex is-align-items-center is-justify-content-space-between is-flex-wrap-wrap">
|
|
122
116
|
<span className="is-size-7 has-text-secondary is-relative">
|
|
123
|
-
{t("overview.lastModified")}{
|
|
124
|
-
<DateFromNow baseDate={baseDate} date={repository.lastModified ?? repository.creationDate} />
|
|
117
|
+
{t("overview.lastModified")} <DateFromNow date={repository.lastModified ?? repository.creationDate} />
|
|
125
118
|
</span>
|
|
126
119
|
<RepositoryFlags repository={repository} />
|
|
127
120
|
</DetailsRow>
|
|
@@ -260,7 +260,6 @@ export const Default: Story = {
|
|
|
260
260
|
// Die Props für die Komponente werden in das `args`-Objekt verschoben.
|
|
261
261
|
source: source,
|
|
262
262
|
repository: repository,
|
|
263
|
-
baseDate: new Date("2020-04-16T09:22:42Z"),
|
|
264
263
|
},
|
|
265
264
|
};
|
|
266
265
|
|
|
@@ -268,7 +267,6 @@ export const Markdown: Story = {
|
|
|
268
267
|
args: {
|
|
269
268
|
source: markdownSource,
|
|
270
269
|
repository: repository,
|
|
271
|
-
baseDate: new Date("2020-04-15T09:47:42Z"),
|
|
272
270
|
},
|
|
273
271
|
};
|
|
274
272
|
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
|
|
17
17
|
import React, { FC, useReducer } from "react";
|
|
18
18
|
import { AnnotatedLine, AnnotatedSource, Repository } from "@scm-manager/ui-types";
|
|
19
|
-
import { DateInput } from "../../useDateFormatter";
|
|
20
19
|
import AnnotatePopover from "./AnnotatePopover";
|
|
21
20
|
import AnnotateLine from "./AnnotateLine";
|
|
22
21
|
import { Action } from "./actions";
|
|
@@ -26,7 +25,6 @@ import { SyntaxHighlighter } from "@scm-manager/ui-syntaxhighlighting";
|
|
|
26
25
|
type Props = {
|
|
27
26
|
source: AnnotatedSource;
|
|
28
27
|
repository: Repository;
|
|
29
|
-
baseDate?: DateInput;
|
|
30
28
|
};
|
|
31
29
|
|
|
32
30
|
type State = {
|
|
@@ -83,7 +81,7 @@ const reducer = (state: State, action: Action): State => {
|
|
|
83
81
|
}
|
|
84
82
|
};
|
|
85
83
|
|
|
86
|
-
const Annotate: FC<Props> = ({ source, repository
|
|
84
|
+
const Annotate: FC<Props> = ({ source, repository }) => {
|
|
87
85
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
88
86
|
|
|
89
87
|
const defaultRenderer: FC = ({ children }: any) => {
|
|
@@ -122,7 +120,6 @@ const Annotate: FC<Props> = ({ source, repository, baseDate }) => {
|
|
|
122
120
|
dispatch={dispatch}
|
|
123
121
|
offsetTop={state.offset}
|
|
124
122
|
repository={repository}
|
|
125
|
-
baseDate={baseDate}
|
|
126
123
|
/>
|
|
127
124
|
);
|
|
128
125
|
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import React, { FC, Dispatch, useRef, ReactNode } from "react";
|
|
18
18
|
import styled from "styled-components";
|
|
19
19
|
import AuthorImage from "./AuthorImage";
|
|
20
|
-
import DateShort from "
|
|
20
|
+
import { DateShort } from "@scm-manager/ui-core";
|
|
21
21
|
import { Action } from "./actions";
|
|
22
22
|
import { AnnotatedLine } from "@scm-manager/ui-types";
|
|
23
23
|
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
import React, { FC, useState, useRef, useLayoutEffect, Dispatch } from "react";
|
|
18
18
|
import styled from "styled-components";
|
|
19
19
|
import { Link } from "react-router-dom";
|
|
20
|
-
import
|
|
20
|
+
import { AbsoluteDate } from "@scm-manager/ui-core";
|
|
21
21
|
import { SingleContributor } from "../changesets";
|
|
22
|
-
import { DateInput } from "../../useDateFormatter";
|
|
23
22
|
import { Repository, AnnotatedLine } from "@scm-manager/ui-types";
|
|
24
23
|
import AuthorImage from "./AuthorImage";
|
|
25
24
|
import { Action } from "./actions";
|
|
@@ -73,11 +72,10 @@ type PopoverProps = {
|
|
|
73
72
|
annotation: AnnotatedLine;
|
|
74
73
|
offsetTop?: number;
|
|
75
74
|
repository: Repository;
|
|
76
|
-
baseDate?: DateInput;
|
|
77
75
|
dispatch: Dispatch<Action>;
|
|
78
76
|
};
|
|
79
77
|
|
|
80
|
-
const AnnotatePopover: FC<PopoverProps> = ({ annotation, offsetTop, repository,
|
|
78
|
+
const AnnotatePopover: FC<PopoverProps> = ({ annotation, offsetTop, repository, dispatch }) => {
|
|
81
79
|
const [t] = useTranslation("repos");
|
|
82
80
|
const [height, setHeight] = useState(125);
|
|
83
81
|
const ref = useRef<HTMLDivElement>(null);
|
|
@@ -113,7 +111,7 @@ const AnnotatePopover: FC<PopoverProps> = ({ annotation, offsetTop, repository,
|
|
|
113
111
|
<AuthorImage person={annotation.author} />
|
|
114
112
|
<SingleContributor person={annotation.author} displayTextOnly={true} />
|
|
115
113
|
</span>
|
|
116
|
-
<
|
|
114
|
+
<AbsoluteDate className="is-pulled-right" date={annotation.when} />
|
|
117
115
|
</PopoverHeading>
|
|
118
116
|
<hr className="my-2" />
|
|
119
117
|
<p>
|
|
@@ -24,7 +24,7 @@ import ChangesetAuthor from "./ChangesetAuthor";
|
|
|
24
24
|
import SignatureIcon from "./SignatureIcon";
|
|
25
25
|
import ChangesetTags from "./ChangesetTags";
|
|
26
26
|
import { parseDescription } from "./changesets";
|
|
27
|
-
import DateFromNow from "
|
|
27
|
+
import { DateFromNow } from "@scm-manager/ui-core";
|
|
28
28
|
import { Changeset, Repository } from "@scm-manager/ui-types";
|
|
29
29
|
import styled from "styled-components";
|
|
30
30
|
import ChangesetId from "./ChangesetId";
|
package/src/Date.stories.tsx
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020 - present Cloudogu GmbH
|
|
3
|
-
*
|
|
4
|
-
* This program is free software: you can redistribute it and/or modify it under
|
|
5
|
-
* the terms of the GNU Affero General Public License as published by the Free
|
|
6
|
-
* Software Foundation, version 3.
|
|
7
|
-
*
|
|
8
|
-
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
9
|
-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
10
|
-
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
11
|
-
* details.
|
|
12
|
-
*
|
|
13
|
-
* You should have received a copy of the GNU Affero General Public License
|
|
14
|
-
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
// import React from "react";
|
|
18
|
-
// import { storiesOf } from "@storybook/react";
|
|
19
|
-
// import DateFromNow from "./DateFromNow";
|
|
20
|
-
// import DateShort from "./DateShort";
|
|
21
|
-
//
|
|
22
|
-
// const baseProps = {
|
|
23
|
-
// timeZone: "Europe/Berlin",
|
|
24
|
-
// baseDate: "2019-10-12T13:56:42+02:00",
|
|
25
|
-
// };
|
|
26
|
-
//
|
|
27
|
-
// const dates = [
|
|
28
|
-
// "2009-06-30T18:30:00+02:00",
|
|
29
|
-
// "2019-06-30T18:30:00+02:00",
|
|
30
|
-
// "2019-10-12T13:56:40+02:00",
|
|
31
|
-
// "2019-10-11T13:56:40+02:00",
|
|
32
|
-
// ];
|
|
33
|
-
//
|
|
34
|
-
// storiesOf("Date", module)
|
|
35
|
-
// .add("Date from now", () => (
|
|
36
|
-
// <div className="p-5">
|
|
37
|
-
// {dates.map((d) => (
|
|
38
|
-
// <p>
|
|
39
|
-
// <DateFromNow date={d} {...baseProps} />
|
|
40
|
-
// </p>
|
|
41
|
-
// ))}
|
|
42
|
-
// </div>
|
|
43
|
-
// ))
|
|
44
|
-
// .add("Short", () => (
|
|
45
|
-
// <div className="p-5">
|
|
46
|
-
// {dates.map((d) => (
|
|
47
|
-
// <p>
|
|
48
|
-
// <DateShort date={d} {...baseProps} />
|
|
49
|
-
// </p>
|
|
50
|
-
// ))}
|
|
51
|
-
// </div>
|
|
52
|
-
// ));
|
|
53
|
-
|
|
54
|
-
import React from "react";
|
|
55
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
56
|
-
|
|
57
|
-
import DateFromNow from "./DateFromNow";
|
|
58
|
-
|
|
59
|
-
const baseProps = {
|
|
60
|
-
timeZone: "Europe/Berlin",
|
|
61
|
-
baseDate: "2019-10-12T13:56:42+02:00",
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const dates = [
|
|
65
|
-
"2009-06-30T18:30:00+02:00",
|
|
66
|
-
"2019-06-30T18:30:00+02:00",
|
|
67
|
-
"2019-10-12T13:56:40+02:00",
|
|
68
|
-
"2019-10-11T13:56:40+02:00",
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
const meta: Meta<typeof DateFromNow> = {
|
|
72
|
-
title: "Components/DateFromNow",
|
|
73
|
-
component: DateFromNow,
|
|
74
|
-
decorators: [(Story) => <div className="p-5">{Story()}</div>],
|
|
75
|
-
tags: ["autodocs"],
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export default meta;
|
|
79
|
-
|
|
80
|
-
type Story = StoryObj<typeof meta>;
|
|
81
|
-
|
|
82
|
-
export const Primary: Story = {
|
|
83
|
-
args: {
|
|
84
|
-
date: dates[3],
|
|
85
|
-
...baseProps,
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const AllExamples: Story = {
|
|
90
|
-
render: () => (
|
|
91
|
-
<div>
|
|
92
|
-
{dates.map((d, i) => (
|
|
93
|
-
<p key={i}>
|
|
94
|
-
<DateFromNow date={d} {...baseProps} />
|
|
95
|
-
</p>
|
|
96
|
-
))}
|
|
97
|
-
</div>
|
|
98
|
-
),
|
|
99
|
-
};
|
package/src/DateElement.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020 - present Cloudogu GmbH
|
|
3
|
-
*
|
|
4
|
-
* This program is free software: you can redistribute it and/or modify it under
|
|
5
|
-
* the terms of the GNU Affero General Public License as published by the Free
|
|
6
|
-
* Software Foundation, version 3.
|
|
7
|
-
*
|
|
8
|
-
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
9
|
-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
10
|
-
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
11
|
-
* details.
|
|
12
|
-
*
|
|
13
|
-
* You should have received a copy of the GNU Affero General Public License
|
|
14
|
-
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import styled from "styled-components";
|
|
18
|
-
|
|
19
|
-
const DateElement = styled.time`
|
|
20
|
-
border-bottom: 1px dotted rgb(219, 219, 219);
|
|
21
|
-
cursor: help;
|
|
22
|
-
`;
|
|
23
|
-
|
|
24
|
-
export default DateElement;
|
package/src/DateFromNow.tsx
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020 - present Cloudogu GmbH
|
|
3
|
-
*
|
|
4
|
-
* This program is free software: you can redistribute it and/or modify it under
|
|
5
|
-
* the terms of the GNU Affero General Public License as published by the Free
|
|
6
|
-
* Software Foundation, version 3.
|
|
7
|
-
*
|
|
8
|
-
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
9
|
-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
10
|
-
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
11
|
-
* details.
|
|
12
|
-
*
|
|
13
|
-
* You should have received a copy of the GNU Affero General Public License
|
|
14
|
-
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import React, { FC } from "react";
|
|
18
|
-
import useDateFormatter, { DateProps } from "./useDateFormatter";
|
|
19
|
-
import DateElement from "./DateElement";
|
|
20
|
-
|
|
21
|
-
type Props = DateProps & {
|
|
22
|
-
className?: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const DateFromNow: FC<Props> = ({ className, ...dateProps }) => {
|
|
26
|
-
const formatter = useDateFormatter(dateProps);
|
|
27
|
-
if (!formatter) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const dateTime = formatter.formatFull();
|
|
32
|
-
return (
|
|
33
|
-
<DateElement className={className} dateTime={dateTime} title={dateTime}>
|
|
34
|
-
{formatter.formatDistance()}
|
|
35
|
-
</DateElement>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default DateFromNow;
|
package/src/DateShort.tsx
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020 - present Cloudogu GmbH
|
|
3
|
-
*
|
|
4
|
-
* This program is free software: you can redistribute it and/or modify it under
|
|
5
|
-
* the terms of the GNU Affero General Public License as published by the Free
|
|
6
|
-
* Software Foundation, version 3.
|
|
7
|
-
*
|
|
8
|
-
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
9
|
-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
10
|
-
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
11
|
-
* details.
|
|
12
|
-
*
|
|
13
|
-
* You should have received a copy of the GNU Affero General Public License
|
|
14
|
-
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import React, { FC } from "react";
|
|
18
|
-
import useDateFormatter, { DateProps } from "./useDateFormatter";
|
|
19
|
-
import DateElement from "./DateElement";
|
|
20
|
-
|
|
21
|
-
type Props = DateProps & {
|
|
22
|
-
className?: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const DateShort: FC<Props> = ({ className, ...dateProps }) => {
|
|
26
|
-
const formatter = useDateFormatter(dateProps);
|
|
27
|
-
if (!formatter) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const dateTime = formatter.formatFull();
|
|
32
|
-
return (
|
|
33
|
-
<DateElement className={className} dateTime={dateTime} title={dateTime}>
|
|
34
|
-
{formatter.formatShort()}
|
|
35
|
-
</DateElement>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default DateShort;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020 - present Cloudogu GmbH
|
|
3
|
-
*
|
|
4
|
-
* This program is free software: you can redistribute it and/or modify it under
|
|
5
|
-
* the terms of the GNU Affero General Public License as published by the Free
|
|
6
|
-
* Software Foundation, version 3.
|
|
7
|
-
*
|
|
8
|
-
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
9
|
-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
10
|
-
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
11
|
-
* details.
|
|
12
|
-
*
|
|
13
|
-
* You should have received a copy of the GNU Affero General Public License
|
|
14
|
-
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { chooseLocale, supportedLocales } from "./useDateFormatter";
|
|
18
|
-
|
|
19
|
-
describe("test choose locale", () => {
|
|
20
|
-
it("should choose de", () => {
|
|
21
|
-
const locale = chooseLocale("de_DE", ["de", "en"]);
|
|
22
|
-
expect(locale).toBe(supportedLocales.de);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("should choose de, even without language array", () => {
|
|
26
|
-
const locale = chooseLocale("de", []);
|
|
27
|
-
expect(locale).toBe(supportedLocales.de);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("should choose es", () => {
|
|
31
|
-
const locale = chooseLocale("de", ["af", "be", "es"]);
|
|
32
|
-
expect(locale).toBe(supportedLocales.es);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("should fallback en", () => {
|
|
36
|
-
const locale = chooseLocale("af", ["af", "be"]);
|
|
37
|
-
expect(locale).toBe(supportedLocales.en);
|
|
38
|
-
});
|
|
39
|
-
});
|
package/src/useDateFormatter.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020 - present Cloudogu GmbH
|
|
3
|
-
*
|
|
4
|
-
* This program is free software: you can redistribute it and/or modify it under
|
|
5
|
-
* the terms of the GNU Affero General Public License as published by the Free
|
|
6
|
-
* Software Foundation, version 3.
|
|
7
|
-
*
|
|
8
|
-
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
9
|
-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
10
|
-
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
11
|
-
* details.
|
|
12
|
-
*
|
|
13
|
-
* You should have received a copy of the GNU Affero General Public License
|
|
14
|
-
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { useTranslation } from "react-i18next";
|
|
18
|
-
import { enUS, de, es } from "date-fns/locale";
|
|
19
|
-
import { formatDistance, format, Locale, parseISO } from "date-fns";
|
|
20
|
-
|
|
21
|
-
type LocaleMap = {
|
|
22
|
-
[key: string]: Locale;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const supportedLocales: LocaleMap = {
|
|
26
|
-
enUS,
|
|
27
|
-
en: enUS,
|
|
28
|
-
de,
|
|
29
|
-
es,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
type Options = {
|
|
33
|
-
addSuffix: boolean;
|
|
34
|
-
locale: Locale;
|
|
35
|
-
timeZone?: string;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const chooseLocale = (language: string, languages?: readonly string[]) => {
|
|
39
|
-
for (const lng of languages || []) {
|
|
40
|
-
const locale = supportedLocales[lng];
|
|
41
|
-
if (locale) {
|
|
42
|
-
return locale;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const locale = supportedLocales[language];
|
|
47
|
-
if (locale) {
|
|
48
|
-
return locale;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return enUS;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export type DateInput = Date | string;
|
|
55
|
-
|
|
56
|
-
export type DateProps = {
|
|
57
|
-
date?: DateInput;
|
|
58
|
-
timeZone?: string;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* baseDate is the date from which the distance is calculated,
|
|
62
|
-
* default is the current time (new Date()). This property
|
|
63
|
-
* is required to keep snapshots tests green over the time on
|
|
64
|
-
* ci server.
|
|
65
|
-
*/
|
|
66
|
-
baseDate?: DateInput;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const createOptions = (locale: Locale, timeZone?: string) => {
|
|
70
|
-
const options: Options = {
|
|
71
|
-
addSuffix: true,
|
|
72
|
-
locale,
|
|
73
|
-
};
|
|
74
|
-
if (timeZone) {
|
|
75
|
-
options.timeZone = timeZone;
|
|
76
|
-
}
|
|
77
|
-
return options;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const createBaseDate = (baseDate?: DateInput) => {
|
|
81
|
-
if (baseDate) {
|
|
82
|
-
return toDate(baseDate);
|
|
83
|
-
}
|
|
84
|
-
return new Date();
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const toDate = (value: DateInput): Date => {
|
|
88
|
-
if (value instanceof Date) {
|
|
89
|
-
return value;
|
|
90
|
-
}
|
|
91
|
-
return parseISO(value);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const useDateFormatter = ({ date, baseDate, timeZone }: DateProps) => {
|
|
95
|
-
const { i18n } = useTranslation();
|
|
96
|
-
if (!date) {
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const isoDate = toDate(date);
|
|
101
|
-
const base = createBaseDate(baseDate);
|
|
102
|
-
|
|
103
|
-
const locale = chooseLocale(i18n.language, i18n.languages);
|
|
104
|
-
const options = createOptions(locale, timeZone);
|
|
105
|
-
return {
|
|
106
|
-
formatShort() {
|
|
107
|
-
return format(isoDate, "yyyy-MM-dd", options);
|
|
108
|
-
},
|
|
109
|
-
formatFull() {
|
|
110
|
-
return format(isoDate, "yyyy-MM-dd HH:mm:ss", options);
|
|
111
|
-
},
|
|
112
|
-
formatDistance() {
|
|
113
|
-
return formatDistance(isoDate, base, options);
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
export default useDateFormatter;
|