Skip to content

Commit

Permalink
Add GitHub information in mobile view
Browse files Browse the repository at this point in the history
- Initial work from @irenejoeunpark with PR #2491 (#2716)
- Changed repos display to row, added border bottom for header, added hint icon for accordion
- Fixed clicking on expand icon copies link to blog post
- Added expand icons in the bottom of the github info
- Added function to auto close accordion when scroll pass post
- Added css for mobile device < 375 px width

Co-authored-by: Francesco Menghi <[email protected]>
  • Loading branch information
TueeNguyen and menghif authored Jan 28, 2022
1 parent 6a072f3 commit d7062de
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 63 deletions.
49 changes: 49 additions & 0 deletions src/web/src/components/Posts/ExpandIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { IconButton, createStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import ExpandLessIcon from '@material-ui/icons/ExpandLess';

type Props = {
small: Boolean;
expandHeader: Boolean;
setExpandHeader: Function;
};

const useStyles = makeStyles(() =>
createStyles({
container: {
display: 'flex',
justifyContent: 'center',
},
smallIcon: {
padding: 0,
fill: '#cccccc',
},
bigIcon: {
fontSize: '5rem',
fill: '#cccccc',
},
iconBtn: {
padding: '5px',
},
})
);
const ExpandIcon = ({ small, expandHeader, setExpandHeader }: Props) => {
const classes = useStyles();
return small ? (
<IconButton onClick={() => setExpandHeader(!expandHeader)} className={classes.iconBtn}>
{expandHeader ? (
<ExpandLessIcon className={classes.smallIcon} />
) : (
<ExpandMoreIcon className={classes.smallIcon} />
)}
</IconButton>
) : (
<div className={classes.container}>
<IconButton onClick={() => setExpandHeader(!expandHeader)} className={classes.iconBtn}>
<ExpandLessIcon className={classes.bigIcon} />
</IconButton>
</div>
);
};
export default ExpandIcon;
2 changes: 1 addition & 1 deletion src/web/src/components/Posts/GitHubInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const parseGitHubUrl = (url: string): URL | null => {
}
};

const filterGitHubUrls = (urls: string[]) => {
export const filterGitHubUrls = (urls: string[]) => {
const issues: Set<string> = new Set();
const pullRequests: Set<string> = new Set();
const repos: Set<string> = new Set();
Expand Down
51 changes: 51 additions & 0 deletions src/web/src/components/Posts/GitHubInfoMobile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { createStyles, makeStyles, Theme, ListSubheader } from '@material-ui/core';
import Repos from './Repos';
import Issues from './Issues';
import PullRequests from './PullRequests';
import Commits from './Commits';
import Users from './Users';
import { filterGitHubUrls } from './GitHubInfo';

type Props = {
ghUrls: string[];
};

const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
padding: '0',
display: 'flex',
flexDirection: 'column',
marginTop: '0',
lineHeight: '1',
[theme.breakpoints.up('lg')]: {
width: '21rem',
},
color: theme.palette.text.secondary,
},
GitHubInfoContainer: {
margin: '0 0 0 1rem',
},
})
);

const GitHubInfoMobile = ({ ghUrls }: Props) => {
const classes = useStyles();
const { repos, issues, pullRequests, commits, users } = filterGitHubUrls(ghUrls);

return (
<div>
<ListSubheader className={classes.root}>
<div className={classes.GitHubInfoContainer}>
{!!repos.length && <Repos repoUrls={repos} />}
{!!issues.length && <Issues issueUrls={issues} />}
{!!pullRequests.length && <PullRequests prUrls={pullRequests} />}
{!!commits.length && <Commits commitUrls={commits} />}
{!!users.length && <Users usernames={users} />}
</div>
</ListSubheader>
</div>
);
};

export default GitHubInfoMobile;
187 changes: 131 additions & 56 deletions src/web/src/components/Posts/Post.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useState, useMemo } from 'react';
import { useRef, useState, useMemo, useEffect } from 'react';
import useSWR from 'swr';
import clsx from 'clsx';
import { makeStyles, Theme, useTheme } from '@material-ui/core/styles';
Expand All @@ -9,6 +9,9 @@ import {
ListSubheader,
createStyles,
useMediaQuery,
Accordion,
AccordionSummary,
AccordionDetails,
Chip,
} from '@material-ui/core';
import ErrorRoundedIcon from '@material-ui/icons/ErrorRounded';
Expand All @@ -19,7 +22,9 @@ import Spinner from '../Spinner';
import PostDesktopInfo from './PostInfo';
import PostAvatar from './PostAvatar';
import GitHubInfo from './GitHubInfo';
import GitHubInfoMobile from './GitHubInfoMobile';
import ShareButton from './ShareButton';
import ExpandIcon from './ExpandIcon';

import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css';

Expand Down Expand Up @@ -61,7 +66,8 @@ const useStyles = makeStyles((theme: Theme) =>
gridTemplateColumns: 'auto auto auto auto',
justifyContent: 'left',
width: '100%',
padding: '1em 0 1em 0',
padding: '1em 0 0 0',
marginBottom: '0',
},
},
video: {
Expand Down Expand Up @@ -104,6 +110,7 @@ const useStyles = makeStyles((theme: Theme) =>
fontSize: 'clamp(2.5em, 4vw, 3em)',
[theme.breakpoints.down(1205)]: {
textAlign: 'start',
fontSize: '2em',
marginLeft: '.3em',
},
[theme.breakpoints.down(1024)]: {
Expand Down Expand Up @@ -183,7 +190,7 @@ const useStyles = makeStyles((theme: Theme) =>
[theme.breakpoints.down(1024)]: {
fontSize: '1.1em',
height: '5px',
margin: '-1.6em 1em -1em .5px',
margin: '-1.6em -.5em .5px',
},
},
authorAvatarContainer: {
Expand Down Expand Up @@ -215,6 +222,30 @@ const useStyles = makeStyles((theme: Theme) =>
width: 'auto',
},
},
accordionSummary: {
marginTop: '0',
paddingRight: '0',
justifyContent: 'flex-end',
overflow: 'hidden',
textOverflow: 'ellipsis',
paddingBottom: '0',
'& .MuiAccordionSummary-content': {
marginBottom: '0.2em',
},
},
accordion: {
backgroundColor: 'inherit',
borderBottom: '1.5px solid #cccccc',
boxShadow: 'none',
top: '0',
zIndex: 1,
position: 'sticky',
},
expandIcon: {
alignSelf: 'center',
borderLeft: '1px solid #cccccc',
paddingLeft: '5px',
},
})
);

Expand Down Expand Up @@ -271,6 +302,7 @@ const PostComponent = ({ postUrl, currentPost, totalPosts }: Props) => {
const desktop = useMediaQuery(theme.breakpoints.up(1205));
// We need a ref to our post content, which we inject into a <section> below.
const sectionEl = useRef<HTMLElement>(null);

// Grab the post data from our backend so we can render it
const { data: post, error } = useSWR<Post>(postUrl);
const isMedia = post?.type === 'video';
Expand All @@ -281,6 +313,23 @@ const PostComponent = ({ postUrl, currentPost, totalPosts }: Props) => {
[post?.html]
);

useEffect(() => {
const onScroll = () => {
// get the distance between the bottom of the blog post and
// the top of the web page
const bottom = sectionEl?.current?.getBoundingClientRect().bottom;
if (bottom && bottom < 1) {
// if bottom reaches top => close header and remove event listener
setExpandHeader(false);
window.removeEventListener('scroll', onScroll);
}
};
// only if header is open, we attach the onScroll function to scroll event
if (expandHeader) {
window.addEventListener('scroll', onScroll);
}
}, [expandHeader]);

if (error) {
console.error(`Error loading post at ${postUrl}`, error);
return (
Expand Down Expand Up @@ -331,63 +380,89 @@ const PostComponent = ({ postUrl, currentPost, totalPosts }: Props) => {
</div>
)}

<ListSubheader component="div" className={classes.postInfo}>
<div className={classes.titleContainer}>
<Typography
variant="h3"
title={post.title}
id={post.id}
className={clsx(classes.title, expandHeader && classes.expandedTitle)}
>
<span
role="button"
tabIndex={0}
onClick={() => setExpandHeader(!expandHeader)}
onKeyDown={() => setExpandHeader(!expandHeader)}
>
{post.title}
</span>
</Typography>
</div>
{!desktop && (
<>
<div className={classes.authorAvatarContainer}>
<PostAvatar name={post.feed.author} url={post.feed.link} />
</div>
<div className={classes.authorNameContainer}>
<h1 className={classes.author}>
<a className={classes.link} href={post.feed.link}>
{post.feed.author}
</a>
</h1>
{desktop ? (
<>
<ListSubheader component="div" className={classes.postInfo}>
<div className={classes.titleContainer}>
<Typography
variant="h3"
title={post.title}
id={post.id}
className={clsx(classes.title, expandHeader && classes.expandedTitle)}
>
<span
role="button"
tabIndex={0}
onClick={() => setExpandHeader(!expandHeader)}
onKeyDown={() => setExpandHeader(!expandHeader)}
>
{post.title}
</span>
</Typography>
</div>
<div className={classes.publishedDateContainer}>
<h1 className={classes.published}>
<a href={post.url} rel="bookmark" className={classes.link}>
<time dateTime={post.updated}>{`${formatPublishedDate(post.updated)}`}</time>
</a>

<ShareButton url={post.url} />
</h1>
</ListSubheader>
<ListSubheader component="div" className={classes.desktopPostInfo}>
<PostDesktopInfo
postUrl={post.url}
authorName={post.feed.author}
postDate={formatPublishedDate(post.updated)}
blogUrl={post.feed.link}
/>
{!!extractedGitHubUrls.length && <GitHubInfo ghUrls={extractedGitHubUrls} />}
</ListSubheader>
</>
) : (
<Accordion
onKeyDown={() => setExpandHeader(!expandHeader)}
expanded={expandHeader}
className={classes.accordion}
>
<AccordionSummary className={classes.accordionSummary}>
<ListSubheader component="div" className={classes.postInfo}>
<div className={classes.titleContainer}>
<Typography
variant="h3"
title={post.title}
id={post.id}
className={clsx(classes.title, expandHeader && classes.expandedTitle)}
>
<span role="button" tabIndex={0}>
{post.title}
</span>
</Typography>
</div>
<div className={classes.authorAvatarContainer}>
<PostAvatar name={post.feed.author} url={post.feed.link} />
</div>
<div className={classes.authorNameContainer}>
<h1 className={classes.author}>
<a className={classes.link} href={post.feed.link}>
{post.feed.author}
</a>
</h1>
</div>
<div className={classes.publishedDateContainer}>
<h1 className={classes.published}>
<a href={post.url} rel="bookmark" className={classes.link}>
<time dateTime={post.updated}>{`${formatPublishedDate(post.updated)}`}</time>
</a>
<ShareButton url={post.url} />
<ExpandIcon small expandHeader={expandHeader} setExpandHeader={setExpandHeader} />
</h1>

<div>
<AdminButtons />
<div>
<AdminButtons />
</div>
</div>
</div>
</>
)}
</ListSubheader>
{desktop && (
<ListSubheader component="div" className={classes.desktopPostInfo}>
<PostDesktopInfo
postUrl={post.url}
authorName={post.feed.author}
postDate={formatPublishedDate(post.updated)}
blogUrl={post.feed.link}
/>
{!!extractedGitHubUrls.length && <GitHubInfo ghUrls={extractedGitHubUrls} />}
</ListSubheader>
</ListSubheader>
</AccordionSummary>
<AccordionDetails>
{!!extractedGitHubUrls.length && <GitHubInfoMobile ghUrls={extractedGitHubUrls} />}
</AccordionDetails>
<ExpandIcon small={false} expandHeader={expandHeader} setExpandHeader={setExpandHeader} />
</Accordion>
)}

<div className={classes.content}>
{isMedia && (
<LiteYouTubeEmbed
Expand Down
7 changes: 3 additions & 4 deletions src/web/src/components/Posts/PostAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ const useStyles = makeStyles((theme: Theme) =>
height: '2.5em',
[theme.breakpoints.down(1200)]: {
fontSize: '2.5em',
width: '2.5em',
height: '2.5em',
},
[theme.breakpoints.down(1024)]: {
fontSize: '2em',
width: '2.5em',
height: '2.5em',
},
[theme.breakpoints.down(375)]: {
fontSize: '1.7em',
},
},
text: {
Expand Down
2 changes: 1 addition & 1 deletion src/web/src/components/Posts/Repos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const useStyles = makeStyles((theme: Theme) =>
repos: {
paddingLeft: 0,
display: 'flex',
flexDirection: 'column',
flexWrap: 'wrap',
gap: '1.5rem',
},
repo: {
Expand Down
Loading

0 comments on commit d7062de

Please sign in to comment.