feat: Version 2

Closes #627, closes #1047
This commit is contained in:
Maksim Eltyshev
2025-05-10 02:09:06 +02:00
parent ad7fb51cfa
commit 2ee1166747
1557 changed files with 76832 additions and 47042 deletions
@@ -0,0 +1,38 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import styles from './ExpirableTime.module.scss';
const DAY = 1000 * 60 * 60 * 24;
const isExpired = (value) => value <= Date.now() - DAY;
const ExpirableTime = React.memo(({ children, date, verboseDate, tooltip, ...props }) => (
<time
{...props} // eslint-disable-line react/jsx-props-no-spreading
dateTime={date.toISOString()}
title={tooltip ? verboseDate : undefined}
className={classNames(isExpired(date) && styles.expired)}
>
{children}
</time>
));
ExpirableTime.propTypes = {
children: PropTypes.string.isRequired,
date: PropTypes.instanceOf(Date).isRequired,
verboseDate: PropTypes.string,
tooltip: PropTypes.bool.isRequired,
};
ExpirableTime.defaultProps = {
verboseDate: undefined,
};
export default ExpirableTime;
@@ -0,0 +1,10 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
:global(#app) {
.expired {
color: #cf513d;
}
}
@@ -0,0 +1,46 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import ReactTimeAgo from 'react-time-ago';
import getDateFormat from '../../../utils/get-date-format';
import ExpirableTime from './ExpirableTime';
const TimeAgo = React.memo(({ date, withExpiration }) => {
const [t, i18n] = useTranslation();
const verboseDateFormatter = useCallback(
(value) =>
t(`format:${getDateFormat(value)}`, {
value,
postProcess: 'formatDate',
}),
[t],
);
return (
<ReactTimeAgo
date={date}
timeStyle="round-minute"
locale={i18n.resolvedLanguage}
component={withExpiration ? ExpirableTime : undefined}
formatVerboseDate={verboseDateFormatter}
/>
);
});
TimeAgo.propTypes = {
date: PropTypes.instanceOf(Date).isRequired,
withExpiration: PropTypes.bool,
};
TimeAgo.defaultProps = {
withExpiration: false,
};
export default TimeAgo;
@@ -0,0 +1,8 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import TimeAgo from './TimeAgo';
export default TimeAgo;