Merge pull request #82 from hyperspacedev/profile-page-81
Redesign profile page
This commit is contained in:
commit
a709872e0a
|
@ -69,7 +69,7 @@
|
|||
],
|
||||
"build": {
|
||||
"appId": "net.marquiskurt.hyperspace",
|
||||
"afterSign": "desktop/notarize.js",
|
||||
"afterSign": "desktop/notarize.js",
|
||||
"directories": {
|
||||
"buildResources": "desktop"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Theme, createStyles } from "@material-ui/core";
|
||||
import { isDarwinApp } from "../utilities/desktop";
|
||||
import { isAppbarExpanded } from "../utilities/appbar";
|
||||
|
||||
export const styles = (theme: Theme) => createStyles({
|
||||
root: {
|
||||
|
@ -69,7 +70,8 @@ export const styles = (theme: Theme) => createStyles({
|
|||
backgroundColor: theme.palette.primary.dark,
|
||||
width: '100%',
|
||||
color: theme.palette.common.white,
|
||||
zIndex: 1
|
||||
zIndex: 1,
|
||||
top: isAppbarExpanded()? 80: 64,
|
||||
},
|
||||
pageHeroBackgroundImage: {
|
||||
position: 'absolute',
|
||||
|
@ -80,18 +82,19 @@ export const styles = (theme: Theme) => createStyles({
|
|||
backgroundSize: 'cover',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
opacity: 0.40,
|
||||
zIndex: -1
|
||||
opacity: 0.35,
|
||||
zIndex: -1,
|
||||
filter: 'blur(2px)'
|
||||
},
|
||||
pageHeroContent: {
|
||||
padding: 16,
|
||||
paddingTop: 116,
|
||||
paddingTop: 8,
|
||||
textAlign: 'center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingLeft: '25%',
|
||||
paddingRight: '25%',
|
||||
paddingLeft: '5%',
|
||||
paddingRight: '5%',
|
||||
},
|
||||
position: "relative",
|
||||
zIndex: 1
|
||||
|
@ -110,6 +113,38 @@ export const styles = (theme: Theme) => createStyles({
|
|||
},
|
||||
//backgroundColor: theme.palette.background.default
|
||||
},
|
||||
profileToolbar: {
|
||||
zIndex: 2,
|
||||
paddingTop: 8,
|
||||
},
|
||||
profileContent: {
|
||||
padding: 16,
|
||||
[theme.breakpoints.up('md')]: {
|
||||
paddingLeft: '5%',
|
||||
paddingRight: '5%',
|
||||
paddingBottom: 48,
|
||||
paddingTop: 24,
|
||||
},
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
display: 'flex',
|
||||
paddingBottom: 24,
|
||||
paddingTop: 24,
|
||||
},
|
||||
profileAvatar: {
|
||||
width: 64,
|
||||
height: 64,
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: 128,
|
||||
height: 128,
|
||||
},
|
||||
backgroundColor: theme.palette.primary.main
|
||||
},
|
||||
profileUserBox: {
|
||||
paddingLeft: theme.spacing.unit * 2
|
||||
},
|
||||
pageProfileAvatar: {
|
||||
width: 128,
|
||||
height: 128,
|
||||
|
@ -120,6 +155,7 @@ export const styles = (theme: Theme) => createStyles({
|
|||
},
|
||||
pageProfileNameEmoji: {
|
||||
height: theme.typography.h4.fontSize,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
},
|
||||
pageProfileStatsDiv: {
|
||||
display: 'inline-flex',
|
||||
|
@ -139,9 +175,9 @@ export const styles = (theme: Theme) => createStyles({
|
|||
pageContentLayoutConstraints: {
|
||||
paddingLeft: theme.spacing.unit,
|
||||
paddingRight: theme.spacing.unit,
|
||||
paddingTop: theme.spacing.unit * 4,
|
||||
paddingTop: theme.spacing.unit * 12,
|
||||
paddingBottom: theme.spacing.unit * 2,
|
||||
[theme.breakpoints.up('md')]: {
|
||||
[theme.breakpoints.up('lg')]: {
|
||||
paddingLeft: theme.spacing.unit * 32,
|
||||
paddingRight: theme.spacing.unit * 32
|
||||
},
|
||||
|
@ -239,5 +275,8 @@ export const styles = (theme: Theme) => createStyles({
|
|||
top: theme.spacing.unit,
|
||||
right: theme.spacing.unit,
|
||||
color: theme.palette.common.white
|
||||
},
|
||||
pageGrow: {
|
||||
flexGrow: 1
|
||||
}
|
||||
});
|
|
@ -1,5 +1,21 @@
|
|||
import React, {Component} from 'react';
|
||||
import {withStyles, Typography, Avatar, Divider, Button, CircularProgress, Paper, Tooltip, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions} from '@material-ui/core';
|
||||
import {
|
||||
withStyles,
|
||||
Typography,
|
||||
Avatar,
|
||||
Divider,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Paper,
|
||||
Tooltip,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
Toolbar,
|
||||
IconButton
|
||||
} from '@material-ui/core';
|
||||
import {styles} from './PageLayout.styles';
|
||||
import Mastodon from 'megalodon';
|
||||
import { Account } from '../types/Account';
|
||||
|
@ -7,10 +23,19 @@ import { Status } from '../types/Status';
|
|||
import { Relationship } from '../types/Relationship';
|
||||
import Post from '../components/Post';
|
||||
import {withSnackbar} from 'notistack';
|
||||
import { LinkableButton, LinkableIconButton } from '../interfaces/overrides';
|
||||
import { LinkableIconButton } from '../interfaces/overrides';
|
||||
import { emojifyString } from '../utilities/emojis';
|
||||
|
||||
import AccountEditIcon from 'mdi-material-ui/AccountEdit';
|
||||
import PersonAddIcon from '@material-ui/icons/PersonAdd';
|
||||
import PersonAddDisabledIcon from '@material-ui/icons/PersonAddDisabled';
|
||||
import AccountMinusIcon from 'mdi-material-ui/AccountMinus';
|
||||
import ChatIcon from '@material-ui/icons/Chat';
|
||||
import AccountRemoveIcon from 'mdi-material-ui/AccountRemove';
|
||||
import AccountHeartIcon from 'mdi-material-ui/AccountHeart';
|
||||
import OpenInNewIcon from '@material-ui/icons/OpenInNew';
|
||||
|
||||
|
||||
|
||||
interface IProfilePageState {
|
||||
account?: Account;
|
||||
|
@ -112,23 +137,6 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
|||
});
|
||||
}
|
||||
|
||||
statElement(classes: any, stat: 'following' | 'followers' | 'posts') {
|
||||
let number = 0;
|
||||
if (this.state.account) {
|
||||
if (stat == 'following') {
|
||||
number = this.state.account.following_count;
|
||||
} else if (stat == 'followers') {
|
||||
number = this.state.account.followers_count;
|
||||
} else if (stat == 'posts') {
|
||||
number = this.state.account.statuses_count;
|
||||
}
|
||||
}
|
||||
return <div className={classes.pageProfileStat}>
|
||||
<Typography variant="h6" color="inherit">{number}</Typography>
|
||||
<Typography color="inherit">{stat}</Typography>
|
||||
</div>;
|
||||
}
|
||||
|
||||
loadMoreTimelinePieces() {
|
||||
const { match: {params}} = this.props;
|
||||
this.setState({ viewDidLoad: false, viewIsLoading: true})
|
||||
|
@ -225,50 +233,73 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
|||
<div className={classes.pageLayoutMinimalConstraints}>
|
||||
<div className={classes.pageHeroBackground}>
|
||||
<div className={classes.pageHeroBackgroundImage} style={{ backgroundImage: this.state.account? `url("${this.state.account.header}")`: `url("")`}}/>
|
||||
<div className={classes.pageHeroContent}>
|
||||
{
|
||||
this.isItMe()?
|
||||
<Tooltip title="Edit profile">
|
||||
<LinkableIconButton to="/you" color="inherit" className={classes.pageHeroToolbar}>
|
||||
<AccountEditIcon/>
|
||||
</LinkableIconButton>
|
||||
</Tooltip>: null
|
||||
}
|
||||
<Avatar className={classes.pageProfileAvatar} src={this.state.account ? this.state.account.avatar: ""}/>
|
||||
<Typography variant="h4" color="inherit" dangerouslySetInnerHTML={{__html: this.state.account? emojifyString(this.state.account.display_name, this.state.account.emojis, classes.pageProfileNameEmoji): ""}}></Typography>
|
||||
<Typography variant="caption" color="inherit">{this.state.account ? '@' + this.state.account.acct: ""}</Typography>
|
||||
<Typography paragraph color="inherit">{this.state.account ? this.state.account.note: ""}</Typography>
|
||||
<Divider/>
|
||||
<div className={classes.pageProfileStatsDiv}>
|
||||
{this.statElement(classes, 'followers')}
|
||||
{this.statElement(classes, 'following')}
|
||||
{this.statElement(classes, 'posts')}
|
||||
<Toolbar className={classes.profileToolbar}>
|
||||
<div className={classes.pageGrow}/>
|
||||
<Tooltip title={
|
||||
this.isItMe()?
|
||||
"You can't follow yourself.":
|
||||
this.state.relationship && this.state.relationship.following?
|
||||
"Unfollow":
|
||||
"Follow"
|
||||
}>
|
||||
<IconButton color={"inherit"} disabled={this.isItMe()} onClick={() => this.toggleFollow()}>
|
||||
{
|
||||
this.isItMe()?
|
||||
<PersonAddDisabledIcon/>:
|
||||
this.state.relationship && this.state.relationship.following?
|
||||
<AccountMinusIcon/>:
|
||||
<PersonAddIcon/>
|
||||
}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={"Send a message or post"}>
|
||||
<LinkableIconButton to={`/compose?acct=${this.state.account? this.state.account.acct: ""}`} color={"inherit"}>
|
||||
<ChatIcon/>
|
||||
</LinkableIconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={this.state.relationship && this.state.relationship.blocking? "Unblock this account": "Block this account"}>
|
||||
<IconButton color={"inherit"} disabled={this.isItMe()} onClick={() => this.toggleBlockDialog()}>
|
||||
{
|
||||
this.state.relationship && this.state.relationship.blocking? <AccountHeartIcon/>: <AccountRemoveIcon/>
|
||||
}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Open in web">
|
||||
<IconButton href={this.state.account? this.state.account.url: ""} target="_blank" rel={"nofollower noreferrer noopener"} color={"inherit"}>
|
||||
<OpenInNewIcon/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{
|
||||
this.isItMe()?
|
||||
<Tooltip title="Edit profile">
|
||||
<LinkableIconButton to="/you" color="inherit">
|
||||
<AccountEditIcon/>
|
||||
</LinkableIconButton>
|
||||
</Tooltip>: null
|
||||
}
|
||||
</Toolbar>
|
||||
<div className={classes.profileContent}>
|
||||
<Avatar className={classes.profileAvatar} src={this.state.account ? this.state.account.avatar: ""}/>
|
||||
<div className={classes.profileUserBox}>
|
||||
<Typography variant="h4" color="inherit" dangerouslySetInnerHTML={
|
||||
{__html: this.state.account?
|
||||
this.state.account.display_name?
|
||||
emojifyString(this.state.account.display_name, this.state.account.emojis, classes.pageProfileNameEmoji)
|
||||
: this.state.account.username
|
||||
: ""}}
|
||||
className={classes.pageProfileNameEmoji}/>
|
||||
<Typography variant="caption" color="inherit">{this.state.account ? '@' + this.state.account.acct: ""}</Typography>
|
||||
<Typography paragraph color="inherit">{
|
||||
this.state.account ?
|
||||
this.state.account.note?
|
||||
this.state.account.note
|
||||
: "No bio provided by user."
|
||||
: "No bio available."
|
||||
}</Typography>
|
||||
<Typography color={"inherit"}>
|
||||
{this.state.account? this.state.account.followers_count: 0} followers | {this.state.account? this.state.account.following_count: 0} following | {this.state.account? this.state.account.statuses_count: 0} posts
|
||||
</Typography>
|
||||
</div>
|
||||
<Divider/>
|
||||
{
|
||||
this.state.relationship?
|
||||
<div>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.pageProfileFollowButton}
|
||||
onClick={() => this.toggleFollow()}
|
||||
disabled={this.state.account? this.state.account.id === JSON.parse(localStorage.getItem('account') as string).id: false}
|
||||
>
|
||||
{this.state.relationship.following? "Unfollow": "Follow"}
|
||||
</Button>
|
||||
|
||||
<LinkableButton to={`/compose?mention=${this.state.account? this.state.account.acct: ""}`} variant="contained" className={classes.pageProfileFollowButton}>Mention</LinkableButton>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={classes.pageProfileFollowButton}
|
||||
disabled={this.state.account? this.state.account.id === JSON.parse(localStorage.getItem('account') as string).id: false}
|
||||
onClick={() => this.toggleBlockDialog()}
|
||||
>
|
||||
{this.state.relationship.blocking? "Unblock": "Block"}
|
||||
</Button>
|
||||
</div>: null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.pageContentLayoutConstraints}>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { isDarwinApp } from "./desktop";
|
||||
|
||||
/**
|
||||
* Determine whether the title bar is being displayed.
|
||||
* This might be useful in cases where styles are dependent on the title bar's visibility, such as heights.
|
||||
*
|
||||
* @returns Boolean dictating if the title bar is visible
|
||||
*/
|
||||
export function isAppbarExpanded(): boolean {
|
||||
return isDarwinApp() || process.env.NODE_ENV === "development";
|
||||
}
|
Loading…
Reference in New Issue