Add profile page UI

This commit is contained in:
Marquis Kurt 2019-03-28 16:46:19 -04:00
parent 7f1351fb3a
commit 911a25506d
6 changed files with 183 additions and 2 deletions

View File

@ -7,6 +7,7 @@ import {Route} from 'react-router-dom';
import AboutPage from './pages/About';
import Settings from './pages/Settings';
import { getUserDefaultBool, getUserDefaultTheme } from './utilities/settings';
import ProfilePage from './pages/ProfilePage';
let theme = setHyperspaceTheme(getUserDefaultTheme());
@ -37,7 +38,7 @@ class App extends Component<any, any> {
<Route path="/public"/>
<Route path="/messages"/>
<Route path="/notifications"/>
<Route path="/profile/:profileId"/>
<Route path="/profile/:profileId" component={ProfilePage}/>
<Route path="/conversation/:conversationId"/>
<Route path="/settings" component={Settings}/>
<Route path="/about" component={AboutPage}/>

View File

@ -53,7 +53,7 @@ export class AppLayout extends Component<any, IAppLayoutState> {
if (process.env.NODE_ENV === "development") {
return (
<div className={classes.titleBarRoot}>
<Typography className={classes.titleBarText}>Careful: you're running Hyperspace in developer mode.</Typography>
<Typography className={classes.titleBarText}>Careful: you're running in developer mode.</Typography>
</div>
);
} else if ((navigator.userAgent.includes("Hyperspace") || navigator.userAgent.includes("Electron")) && navigator.userAgent.includes("Macintosh")) {

View File

@ -4,8 +4,10 @@ import App from './App';
import { HashRouter } from 'react-router-dom';
import * as serviceWorker from './serviceWorker';
import {createUserDefaults} from './utilities/settings';
import {refreshUserAccountData} from './utilities/accounts';
createUserDefaults();
refreshUserAccountData();
ReactDOM.render(
<HashRouter>

View File

@ -17,6 +17,44 @@ export const styles = (theme: Theme) => createStyles({
paddingRight: theme.spacing.unit * 24
},
},
pageLayoutMinimalConstraints: {
flexGrow: 1,
[theme.breakpoints.up('md')]: {
marginLeft: 250,
},
},
pageHeroBackground: {
position: 'relative',
height: '100%',
backgroundColor: theme.palette.primary.dark,
width: '100%',
color: theme.palette.common.white,
zIndex: 1
},
pageHeroBackgroundImage: {
position: 'absolute',
bottom: 0,
left: 0,
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
height: '100%',
width: '100%',
opacity: 0.40,
zIndex: -1
},
pageHeroContent: {
padding: 16,
paddingTop: 116,
textAlign: 'center',
width: '100%',
height: '100%',
[theme.breakpoints.up('md')]: {
paddingLeft: '25%',
paddingRight: '25%',
},
zIndex: 1
},
pageListConstraints: {
paddingLeft: theme.spacing.unit,
paddingRight: theme.spacing.unit,
@ -24,5 +62,37 @@ export const styles = (theme: Theme) => createStyles({
paddingLeft: theme.spacing.unit * 2,
paddingRight: theme.spacing.unit * 2
}
},
pageProfileAvatar: {
width: 128,
height: 128,
marginLeft: 'auto',
marginRight: 'auto',
marginBottom: theme.spacing.unit,
backgroundColor: theme.palette.primary.main
},
pageProfileStatsDiv: {
display: 'inline-flex',
marginTop: theme.spacing.unit * 2,
marginBottom: theme.spacing.unit * 2,
},
pageProfileStat: {
marginLeft: theme.spacing.unit,
marginRight: theme.spacing.unit
},
pageProfileFollowButton: {
marginTop: theme.spacing.unit,
marginLeft: theme.spacing.unit,
marginRight: theme.spacing.unit,
zIndex: 3
},
pageContentLayoutConstraints: {
paddingLeft: theme.spacing.unit * 4,
paddingRight: theme.spacing.unit * 4,
paddingTop: theme.spacing.unit * 4,
[theme.breakpoints.up('md')]: {
paddingLeft: theme.spacing.unit * 24,
paddingRight: theme.spacing.unit * 24
},
}
});

99
src/pages/ProfilePage.tsx Normal file
View File

@ -0,0 +1,99 @@
import React, {Component} from 'react';
import {withStyles, Typography, Avatar, Divider, Button} from '@material-ui/core';
import {styles} from './PageLayout.styles';
import Mastodon from 'megalodon';
import { Account } from '../types/Account';
interface IProfilePageState {
id: string;
display_name: string;
acct: string;
followers_count: number;
following_count: number;
status_count: number;
statuses: [];
avatar: string;
header: string;
note: string;
}
class ProfilePage extends Component<any, IProfilePageState> {
constructor(props: any) {
super(props);
const { match: { params }} = this.props;
let client = new Mastodon(localStorage.getItem('account_token') as string, localStorage.getItem('baseurl') + "/api/v1");
client.get(`/accounts/${params.profileId}`).then((resp: any) => {
let profile: Account = resp.data;
const div = document.createElement('div');
div.innerHTML = profile.note;
const note = div.textContent || div.innerText || "";
this.setState({
id: profile.id,
display_name: profile.display_name,
acct: '@' + profile.acct,
followers_count: profile.followers_count,
following_count: profile.following_count,
status_count: profile.statuses_count,
avatar: profile.avatar_static,
header: profile.header_static,
note: note
})
})
}
statElement(classes: any, stat: 'following' | 'followers' | 'posts') {
let number = 0;
if (this.state) {
if (stat == 'following') {
number = this.state.following_count;
} else if (stat == 'followers') {
number = this.state.followers_count;
} else if (stat == 'posts') {
number = this.state.status_count;
}
}
return <div className={classes.pageProfileStat}>
<Typography variant="h6" color="inherit">{number}</Typography>
<Typography color="inherit">{stat}</Typography>
</div>;
}
render() {
const { classes } = this.props;
return(
<div className={classes.pageLayoutMinimalConstraints}>
<div className={classes.pageHeroBackground}>
<div className={classes.pageHeroBackgroundImage} style={{ backgroundImage: this.state? `url("${this.state.header}")`: `url("")`}}/>
<div className={classes.pageHeroContent}>
<Avatar className={classes.pageProfileAvatar} src={this.state ? this.state.avatar: ""}/>
<Typography variant="h4" color="inherit">{this.state? this.state.display_name: ""}</Typography>
<Typography variant="caption" color="inherit">{this.state? this.state.acct: ""}</Typography>
<Typography paragraph color="inherit">{this.state? this.state.note: ""}</Typography>
<Divider/>
<div className={classes.pageProfileStatsDiv}>
{this.statElement(classes, 'followers')}
{this.statElement(classes, 'following')}
{this.statElement(classes, 'posts')}
</div>
<Divider/>
<Button variant="contained" color="primary" className={classes.pageProfileFollowButton}>Follow</Button>
<Button variant="contained" className={classes.pageProfileFollowButton}>Mention</Button>
<Button variant="contained" className={classes.pageProfileFollowButton}>Block</Button>
</div>
</div>
<div className={classes.pageContentLayoutConstraints}>
<Typography variant="h6">Looks like no one's posted here yet.</Typography>
<Typography>Why not give a nidge to start the conversation?</Typography>
</div>
</div>
);
}
}
export default withStyles(styles)(ProfilePage)

View File

@ -0,0 +1,9 @@
import Mastodon from "megalodon";
export function refreshUserAccountData() {
let client = new Mastodon(localStorage.getItem('access_token') as string, localStorage.getItem('baseurl') as string + "/api/v1/");
client.get('/accounts/verify_credentials').then((resp: any) => {
if (JSON.stringify(resp.data) !== localStorage.getItem('account'))
localStorage.setItem('account', JSON.stringify(resp.data));
});
}