Skip to content

Commit

Permalink
OCT-2110 Implement support for markdown && OCT-2108 Implement logic f…
Browse files Browse the repository at this point in the history
…or more than 5 milestones (#532)
  • Loading branch information
aziolek authored Oct 25, 2024
2 parents 2121af6 + e1ab893 commit ba7d5d0
Show file tree
Hide file tree
Showing 7 changed files with 1,316 additions and 65 deletions.
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@sentry/react": "^8.4.0",
"@sentry/vite-plugin": "^2.17.0",
"@tanstack/react-query": "^5.37.1",
"@uiw/react-markdown-preview": "^5.1.3",
"@vimeo/player": "^2.24.0",
"@wagmi/core": "^2.11.5",
"axios": "^1.7.2",
Expand All @@ -56,7 +57,6 @@
"react-dom": "^18.3.1",
"react-i18next": "^14.1.2",
"react-infinite-scroller": "^1.2.6",
"react-lines-ellipsis": "^0.15.4",
"react-router-dom": "^6.23.1",
"react-slider": "^2.0.6",
"react-toastify": "^10.0.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
$milestoneHorizontalPadding: 2.4rem;
$milestoneLineHeight: 2rem;
$milestoneParagraphMargin: 0.5rem;
$milestoneReadMoreButtonBackground: 1.5 * $milestoneLineHeight;
$milestoneReadMoreFadeOutHeight: $milestoneLineHeight + $milestoneParagraphMargin;

.root {
padding: 0 3.2rem;

&.isFetching {
margin-bottom: 1.6rem;
}

@media #{$tablet-up} {
padding: 0 $projectListItemHorizontalPaddingTabletUp;
}
Expand Down Expand Up @@ -31,6 +41,23 @@
height: 8.8rem;
}

.reportingAndNumber {
display: flex;
align-items: center;
}

.milestonesNumber {
display: flex;
align-items: center;
justify-content: center;
font-size: $font-size-14;
background: $color-octant-grey1;
border-radius: $border-radius-08;
height: 2.4rem;
padding: 0.5rem 1rem;
margin-left: 1rem;
}

.filters {
display: flex;
height: 4rem;
Expand Down Expand Up @@ -79,11 +106,12 @@
}

.milestone {
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
background: $color-white;
padding: 2rem 2.4rem;
padding: 2rem $milestoneHorizontalPadding;
border-radius: $border-radius-20;
margin-top: 1.6rem;

Expand All @@ -101,13 +129,30 @@
}

.title {
text-align: left;
font-weight: $font-weight-bold;
font-size: $font-size-18;
margin-bottom: 0.5rem;
}

.body {
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;

&.isExpandable {
max-height: 11rem;
padding-bottom: 1rem;
}

&.isExpanded {
max-height: none;
padding-bottom: 3rem;
}
}

.description {
white-space: pre-wrap;
text-align: left;
font-size: $font-size-14;
color: $color-octant-grey5;
Expand All @@ -116,14 +161,50 @@
padding-top: 0.8rem;
margin-top: 1rem;

p, ul, ol, li {
font-size: $font-size-14;
font-family: 'Inter', sans-serif;
color: $color-octant-grey5 !important;
margin-bottom: 0;
line-height: $milestoneLineHeight;
}

a {
@include buttonVariantLink3($font-size-14);
}

.date {
font-size: $font-size-10;
padding: 0.8rem 0;
}
}

.blur {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: $milestoneReadMoreButtonBackground;
background: $color-white;

&::before {
content: '';
position: absolute;
bottom: 100%;
left: 0;
width: 100%;
height: $milestoneReadMoreFadeOutHeight;
opacity: 0.75;
background: $color-white;
}
}
}

.buttonExpand {
position: absolute;
bottom: 1rem;
left: $milestoneHorizontalPadding;
z-index: $z-index-2;
font-size: $font-size-14 // button variant link3 has font-size-16, but here 14.
}

Expand Down
103 changes: 61 additions & 42 deletions client/src/components/Project/ProjectMilestones/ProjectMilestones.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import MarkdownPreview from '@uiw/react-markdown-preview';
import cx from 'classnames';
import { format } from 'date-fns';
import React, { FC, useState } from 'react';
import { useTranslation } from 'react-i18next';
import LinesEllipsis from 'react-lines-ellipsis';
import { useParams } from 'react-router-dom';

import ProjectMilestonesNoResults from 'components/Project/ProjectMilestonesNoResults';
Expand All @@ -16,11 +16,14 @@ import { pending, completed } from 'svg/projectMilestones';
import styles from './ProjectMilestones.module.scss';
import ProjectMilestonesProps from './types';

const MILESTONE_MAX_HEIGHT_CLIPPED = 110; // pixels.
const MIELSTONES_MAX_LENGTH_CLIPPED = 5;

const ProjectMilestones: FC<ProjectMilestonesProps> = ({ projectAddress }) => {
const { t } = useTranslation('translation', { keyPrefix: 'views.project.milestones' });
const [filter, setFilter] = useState<'all' | 'pending' | 'complete'>('all');
const [expandedMilestoneId, setExpandedMilestoneId] = useState<string>('');
const [milestonesIdsWithReadMore, setMilestonesIdsWithReadMore] = useState<string[]>([]);
const [milestonesExpandable, setMilestonesExpandable] = useState<string[]>([]);
const { isMobile } = useMediaQuery();

const { epoch } = useParams();
Expand All @@ -31,19 +34,6 @@ const ProjectMilestones: FC<ProjectMilestonesProps> = ({ projectAddress }) => {

const getDateFormatted = (date: string | number): string => format(date, 'd LLL');

const handleReflow = (id: string, isClamped: boolean) => {
if (!isClamped) {
return;
}

setMilestonesIdsWithReadMore(prevState => {
if (prevState.includes(id)) {
return prevState;
}
return [...prevState, id];
});
};

const states = [
{
filter: 'all',
Expand All @@ -61,12 +51,19 @@ const ProjectMilestones: FC<ProjectMilestonesProps> = ({ projectAddress }) => {
},
];

const areMilestonesAvailable = !isFetching && data !== undefined;
const areMilestonesAvailable = !isFetching && data !== undefined && data.milestones.length > 0;
const areMilestonesClipped =
areMilestonesAvailable && data.milestones.length > MIELSTONES_MAX_LENGTH_CLIPPED;

return (
<div className={styles.root}>
<div className={cx(styles.root, isFetching && styles.isFetching)}>
<div className={styles.header}>
{t('header')}
<div className={styles.reportingAndNumber}>
{t('header')}
{areMilestonesAvailable && (
<div className={styles.milestonesNumber}>{data.milestones.length}</div>
)}
</div>
{areMilestonesAvailable ? (
<div className={styles.filters}>
{states.map(({ filter: elementFilter, label, icon }) => {
Expand All @@ -83,20 +80,22 @@ const ProjectMilestones: FC<ProjectMilestonesProps> = ({ projectAddress }) => {
})}
</div>
) : (
<div className={styles.filtersNoMilestones}>No milestones yet</div>
<div className={styles.filtersNoMilestones}>{t('noMilestonesYet')}</div>
)}
</div>
{!isFetching && data === undefined && <ProjectMilestonesNoResults />}
{!isFetching && (data === undefined || data.milestones.length === 0) && (
<ProjectMilestonesNoResults />
)}
{isFetching &&
data === undefined &&
[...Array(5).keys()].map(element => (
<ProjectMilestonesSkeleton key={element} className={styles.milestone} />
))}
{areMilestonesAvailable &&
data?.milestones.slice(0, 5).map((element, index) => {
data?.milestones.slice(0, MIELSTONES_MAX_LENGTH_CLIPPED).map((element, index) => {
const isCompleted = !!element?.completed;
const isPending = !isCompleted;
const isReadMoreVisible = milestonesIdsWithReadMore.includes(element.uid);
const isExpandable = milestonesExpandable.includes(element.uid);
const isExpanded = expandedMilestoneId === element.uid;

if ((filter === 'pending' && isCompleted) || (filter === 'complete' && isPending)) {
Expand All @@ -117,28 +116,48 @@ const ProjectMilestones: FC<ProjectMilestonesProps> = ({ projectAddress }) => {
{getDateFormatted(element.data.endsAt * 1000)}
</div>
<div className={styles.title}>{element.data.title}</div>
<div className={styles.description}>
<LinesEllipsis
ellipsis=" ..."
maxLine={isExpanded ? '999' : '3'}
onReflow={({ clamped: isClamped }) => handleReflow(element.uid, isClamped)}
text={element.data.description}
/>
</div>
{isCompleted && (
<div
ref={div => {
if (div === null) {
return;
}
if (div.clientHeight > MILESTONE_MAX_HEIGHT_CLIPPED) {
setMilestonesExpandable(prevState => {
if (prevState.includes(element.uid)) {
return prevState;
}
return [...prevState, element.uid];
});
}
}}
className={cx(
styles.body,
isExpandable && styles.isExpandable,
isExpanded && styles.isExpanded,
)}
>
<div className={styles.description}>
<div className={styles.date}>
{t('posted')} {getDateFormatted(element.completed.status.createdAt)}
</div>
<LinesEllipsis
ellipsis=" ..."
maxLine={isExpanded ? '999' : '3'}
onReflow={({ clamped: isClamped }) => handleReflow(element.uid, isClamped)}
text={element.completed.status.data.reason}
<MarkdownPreview
source={element.data.description}
/* eslint-disable-next-line @typescript-eslint/naming-convention */
wrapperElement={{ 'data-color-mode': 'light' }}
/>
</div>
)}
{isReadMoreVisible && (
{isCompleted && (
<div className={styles.description}>
<div className={styles.date}>
{t('posted')} {getDateFormatted(element.completed.status.createdAt)}
</div>
<MarkdownPreview
source={element.completed.status.data.reason}
/* eslint-disable-next-line @typescript-eslint/naming-convention */
wrapperElement={{ 'data-color-mode': 'light' }}
/>
</div>
)}
{isExpandable && !isExpanded && <div className={styles.blur} />}
</div>
{isExpandable && (
<Button
className={styles.buttonExpand}
label={isExpanded ? t('buttonExpand.readLess') : t('buttonExpand.readMore')}
Expand All @@ -158,7 +177,7 @@ const ProjectMilestones: FC<ProjectMilestonesProps> = ({ projectAddress }) => {
className={styles.buttonViewKarma}
hasLinkArrow
href={`https://gap.karmahq.xyz/project/${data?.project.details.data.slug}/grants/${data?.uid}/milestones-and-updates#all`}
label={t('viewOnKarmaGap')}
label={areMilestonesClipped ? t('viewMoreOnKarmaGap') : t('viewOnKarmaGap')}
variant="secondary"
/>
)}
Expand Down
11 changes: 1 addition & 10 deletions client/src/components/ui/Button/Button.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,7 @@ $paddingVertical: 1rem;
}

&link3 {
position: relative;
height: auto;
display: inline;
color: $color-octant-green;
padding: 0;
font-size: 1.6rem;

&:hover {
text-decoration: underline;
}
@include buttonVariantLink3();
}

&link4 {
Expand Down
4 changes: 3 additions & 1 deletion client/src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -519,11 +519,13 @@
"header": "Reporting",
"milestone": "Milestone",
"posted": "Posted",
"noMilestonesYet": "No milestones yet",
"buttonExpand": {
"readMore": "Read more",
"readLess": "Read less"
},
"viewOnKarmaGap": "View on KarmaGap",
"viewMoreOnKarmaGap": "View more on KarmaGap",
"noResults": {
"header": "Nothing to report yet. Check back again soon",
"description": "Are you a project admin? Add your reporting <0>here</0>"
Expand Down Expand Up @@ -571,4 +573,4 @@
"information": "We're synchronizing things to prepare the<br/>next epoch, so the app will be unavailable<br/>for a little while. Please check back soon."
}
}
}
}
13 changes: 13 additions & 0 deletions client/src/styles/utils/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,16 @@
max-width: 141.5rem;
}
}

@mixin buttonVariantLink3($font-size: $font-size-16) {
position: relative;
height: auto;
display: inline;
color: $color-octant-green;
padding: 0;
font-size: $font-size;

&:hover {
text-decoration: underline;
}
}
Loading

0 comments on commit ba7d5d0

Please sign in to comment.