Add profile page UI
This commit is contained in:
parent
7f1351fb3a
commit
911a25506d
|
@ -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}/>
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
},
|
||||
}
|
||||
});
|
|
@ -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)
|
|
@ -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));
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue