Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/text expansion #248

Merged
merged 2 commits into from May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 10 additions & 7 deletions components/ArticleItem.js
Expand Up @@ -5,8 +5,8 @@ import ArticleInfo from './ArticleInfo';
import ReplyItem from './ReplyItem';
import ReplyFeedback from './ReplyFeedback';
import { t } from 'ttag';
import TextExpansion from './TextExpansion';
// import ArticleItemWidget from './ArticleItemWidget/ArticleItemWidget.js';
import { nl2br } from 'lib/text';
import ExpandableText from './ExpandableText';

const useStyles = makeStyles(theme => ({
root: {
Expand Down Expand Up @@ -88,9 +88,12 @@ const useStyles = makeStyles(theme => ({
zIndex: 2,
},
},
contentContainer: {
// fix display: box display
content: {
// fix very very long string layout
lineBreak: 'anywhere',
minWidth: 1,
margin: '12px 0',
flex: 1,
},
}));

Expand Down Expand Up @@ -127,9 +130,9 @@ export default function ArticleItem({
</div>
</div>
)}
<div className={classes.contentContainer}>
<TextExpansion content={text} disable={isLink} />
</div>
<ExpandableText className={classes.content} lineClamp={3}>
{nl2br(text)}
</ExpandableText>
</div>
</>
);
Expand Down
145 changes: 95 additions & 50 deletions components/ExpandableText.js
@@ -1,62 +1,107 @@
import React from 'react';
import React, { useState, useEffect, useRef } from 'react';
import { t } from 'ttag';
import { truncate } from 'lib/text';
import { withStyles, makeStyles } from '@material-ui/core';

export default class ExpandableText extends React.Component {
static defaultProps = {
children: '',
wordCount: 140,
};
const useStyles = makeStyles(theme => ({
root: {
width: '100%',
position: 'relative',
overflow: 'hidden',
},
toggleButtonContainer: {
position: 'absolute',
right: 0,
bottom: 0,
paddingLeft: '3em',
backgroundImage: `linear-gradient(90deg, rgba(255,255,255,0) 0%, ${theme.palette.common.white} 30%, ${theme.palette.common.white} 100%)`,
},
}));

state = {
isExpanded: false,
};
const ToggleButton = withStyles({
root: {
border: 0,
color: '#2079F0',
outline: 'none',
cursor: 'pointer',
background: 'transparent',
},
})(({ classes, toggleExpand, expanded }) => (
<button className={classes.root} onClick={toggleExpand}>
({expanded ? t`Show Less` + ' ▲' : t`Show More` + ' ▼'})
</button>
));

toggleExpand = () => {
this.setState(({ isExpanded }) => ({ isExpanded: !isExpanded }));
};
const ExpandableText = ({ className, lineClamp, wordCount = 40, children }) => {
const [expanded, setExpanded] = useState(false);
const [height, setHeight] = useState(0);
const [lineHeight, setLineHeight] = useState(16);
const rootRef = useRef(null);
const containerRef = useRef(null);
const classes = useStyles();

renderToggleButton = () => {
const { isExpanded } = this.state;
return (
<button
key="expandable-text-more-button"
className="more"
onClick={this.toggleExpand}
>
{isExpanded ? '隱藏全文' : '閱讀更多'}
<style jsx>{`
.more {
border: 0;
background: transparent;
text-decoration: underline;
}
`}</style>
</button>
);
const toggleExpand = () => setExpanded(!expanded);

const cloneAndComputeHeight = () => {
const computedStyle = window.getComputedStyle(containerRef.current);
setLineHeight(parseFloat(computedStyle.lineHeight));
const clone = containerRef.current.cloneNode(true);
clone.style.maxHeight = '';
rootRef.current.appendChild(clone);
setHeight(parseFloat(window.getComputedStyle(clone).height));
rootRef.current.removeChild(clone);
};

render() {
const { children, wordCount } = this.props;
const { isExpanded } = this.state;

// Note: if "children" is short enough, this.state.isExpanded should never be true.
//
if (isExpanded) {
return (
<div>
{children}
{this.renderToggleButton()}
</div>
);
useEffect(() => {
if (lineClamp) {
cloneAndComputeHeight();
}
}, []);

const renderWithLineChampLimits = () => {
MrOrz marked this conversation as resolved.
Show resolved Hide resolved
return (
<div>
{truncate(children, {
wordCount,
moreElem: this.renderToggleButton(),
})}
<div
ref={containerRef}
className={classes.root}
style={{ maxHeight: expanded ? undefined : lineHeight * lineClamp }}
>
{children}
{height >= lineHeight * lineClamp && (
<div className={classes.toggleButtonContainer}>
<ToggleButton toggleExpand={toggleExpand} expanded={expanded} />
</div>
)}
</div>
);
}
}
};

const renderWithWordCountLimits = () =>
expanded ? (
<>
{children}
<ToggleButton toggleExpand={toggleExpand} expanded={expanded} />
</>
) : (
truncate(children, {
wordCount,
// eslint-disable-next-line react/display-name
moreElem: (() => (
<ToggleButton
key="expandable-text-more-button"
toggleExpand={toggleExpand}
expanded={expanded}
/>
))(),
})
);

// Note: if "children" is short enough, expanded should never be true.
//
return (
<div className={className} ref={rootRef}>
{lineClamp ? renderWithLineChampLimits() : renderWithWordCountLimits()}
</div>
);
};

export default ExpandableText;
12 changes: 10 additions & 2 deletions components/ReplyItem.js
Expand Up @@ -4,7 +4,7 @@ import gql from 'graphql-tag';
import { t } from 'ttag';
import { TYPE_NAME } from '../constants/replyType';
import Avatar from 'components/AppLayout/Widgets/Avatar';
import TextExpansion from './TextExpansion';
import ExpandableText from './ExpandableText';
import ReplyFeedback from './ReplyFeedback';
import { format, formatDistanceToNow } from 'lib/dateWithLocale';
import isValid from 'date-fns/isValid';
Expand Down Expand Up @@ -58,6 +58,12 @@ const useStyles = makeStyles(theme => ({
height: 72,
},
},
content: {
// fix very very long string layout
lineBreak: 'anywhere',
margin: '12px 0',
flex: 1,
},
}));

/**
Expand Down Expand Up @@ -94,7 +100,9 @@ function ReplyItem({
<div
className={classes.replyType}
>{t`${userName} consider this ${TYPE_NAME[replyType]}`}</div>
<TextExpansion content={text} />
<ExpandableText className={classes.content} lineClamp={3}>
{text}
</ExpandableText>
<div className={classes.status}>
<ReplyFeedback
articleId={articleId}
Expand Down
81 changes: 0 additions & 81 deletions components/TextExpansion.js

This file was deleted.