Merge pull request #85 from hyperspacedev/small-refinements-b

Small refinements and touch-ups
This commit is contained in:
Marquis Kurt 2019-09-23 13:34:49 -04:00 committed by GitHub
commit 1a4d4120aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 6585 additions and 6097 deletions

94
package-lock.json generated
View File

@ -1297,6 +1297,12 @@
"@types/react": "*"
}
},
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
"dev": true
},
"@types/history": {
"version": "4.7.2",
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.2.tgz",
@ -1491,12 +1497,13 @@
"@types/unist": "*"
}
},
"@types/ws": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.3.tgz",
"integrity": "sha512-yBTM0P05Tx9iXGq00BbJPo37ox68R5vaGTXivs6RGh/BQ6QP5zqZDGWdAO6JbRE/iR1l80xeGAwCQS2nMV9S/w==",
"@types/websocket": {
"version": "0.0.40",
"resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-0.0.40.tgz",
"integrity": "sha512-ldteZwWIgl9cOy7FyvYn+39Ah4+PfpVE72eYKw75iy2L0zTbhbcwvzeJ5IOu6DQP93bjfXq0NGHY6FYtmYoqFQ==",
"dev": true,
"requires": {
"@types/events": "*",
"@types/node": "*"
}
},
@ -12191,19 +12198,19 @@
"dev": true
},
"megalodon": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/megalodon/-/megalodon-1.0.3.tgz",
"integrity": "sha512-RcJT3HRWCXQcE5ZQUpLEjJ+HgWvwoTpXr4XLUf0tWrtmxrDnIW43pOASDb3G7MOBKYonzM1pMfAmR2Yfh3Qw/g==",
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/megalodon/-/megalodon-0.6.4.tgz",
"integrity": "sha512-WGYhcSxGYlBwZSm5VebxLqnbpPemum9/6lJUi1HBsVzF5jXc9fdumhXH0vqGhWdovdqRT86iXBDJl5SwUrbr2A==",
"dev": true,
"requires": {
"@types/oauth": "^0.9.0",
"@types/request": "^2.47.0",
"@types/ws": "^6.0.1",
"axios": "^0.18.1",
"@types/websocket": "0.0.40",
"axios": "^0.18.0",
"oauth": "^0.9.15",
"request": "^2.87.0",
"typescript": "^3.4.5",
"ws": "^7.0.1"
"typescript": "^2.9.1",
"websocket": "^1.0.28"
},
"dependencies": {
"axios": {
@ -12247,19 +12254,10 @@
"dev": true
},
"typescript": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
"integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
"dev": true
},
"ws": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz",
"integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==",
"dev": true,
"requires": {
"async-limiter": "^1.0.0"
}
}
}
},
@ -19851,6 +19849,15 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"dev": true,
"requires": {
"is-typedarray": "^1.0.0"
}
},
"typescript": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.1.tgz",
@ -21010,6 +21017,41 @@
}
}
},
"websocket": {
"version": "1.0.30",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.30.tgz",
"integrity": "sha512-aO6klgaTdSMkhfl5VVJzD5fm+Srhh5jLYbS15+OiI1sN6h/RU/XW6WN9J1uVIpUKNmsTvT3Hs35XAFjn9NMfOw==",
"dev": true,
"requires": {
"debug": "^2.2.0",
"nan": "^2.14.0",
"typedarray-to-buffer": "^3.1.5",
"yaeti": "^0.0.6"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"nan": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
"dev": true
}
}
},
"websocket-driver": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
@ -21368,6 +21410,12 @@
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
"dev": true
},
"yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=",
"dev": true
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",

View File

@ -25,10 +25,10 @@
"file-dialog": "^0.0.7",
"material-ui-pickers": "^2.2.4",
"mdi-material-ui": "^5.13.0",
"megalodon": "^1.0.3",
"megalodon": "^0.6.4",
"moment": "^2.24.0",
"notistack": "^0.5.1",
"prettier": "^1.18.2",
"prettier": "1.18.2",
"query-string": "^6.8.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 3.3 MiB

View File

@ -20,7 +20,6 @@ import MessagesPage from "./pages/Messages";
import RecommendationsPage from "./pages/Recommendations";
import Missingno from "./pages/Missingno";
import You from "./pages/You";
import Blocked from "./pages/Blocked";
import { withSnackbar } from "notistack";
import { PrivateRoute } from "./interfaces/overrides";
import { userLoggedIn } from "./utilities/accounts";
@ -57,8 +56,6 @@ class App extends Component<any, any> {
removeBodyBackground() {
if (isDarwinApp()) {
document.body.style.backgroundColor = "transparent";
console.log("Changed!");
console.log(`New color: ${document.body.style.backgroundColor}`);
}
}
@ -91,9 +88,7 @@ class App extends Component<any, any> {
component={Conversation}
/>
<PrivateRoute path="/search" component={SearchPage} />
<PrivateRoute path="/blocked" component={Blocked} />
<PrivateRoute path="/settings" component={Settings} />
<PrivateRoute path="/you" component={You} />
<PrivateRoute path="/about" component={AboutPage} />
<PrivateRoute path="/compose" component={Composer} />

View File

@ -46,7 +46,7 @@ export const styles = (theme: Theme) =>
borderBottomColor: darken(theme.palette.primary.dark, 0.2),
borderBottomWidth: 1,
borderBottomStyle: isDarwinApp() ? "solid" : "none",
boxShadow: isDarwinApp() ? "none" : "inherit"
boxShadow: isDarwinApp() ? "none" : theme.shadows["4"]
},
appBarMenuButton: {
marginLeft: -12,

View File

@ -103,7 +103,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
this.setState({ currentUser: data });
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't find profile info: " + err.name);
this.props.enqueueSnackbar(
"Couldn't find profile info: " + err.name
);
console.error(err.message);
});
}
@ -113,7 +115,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
let config: Config = result;
this.setState({
enableFederation: config.federation.enablePublicTimeline,
brandName: config.branding ? config.branding.name : "Hyperspace",
brandName: config.branding
? config.branding.name
: "Hyperspace",
developerMode: config.developer
});
}
@ -142,40 +146,53 @@ export class AppLayout extends Component<any, IAppLayoutState> {
switch (notif.type) {
case "favourite":
primaryMessage =
(notif.account.display_name || "@" + notif.account.username) +
(notif.account.display_name ||
"@" + notif.account.username) +
" favorited your post.";
if (notif.status) {
const div = document.createElement("div");
div.innerHTML = notif.status.content;
secondaryMessage =
(div.textContent || div.innerText || "").slice(0, 100) + "...";
(div.textContent || div.innerText || "").slice(
0,
100
) + "...";
}
break;
case "follow":
primaryMessage =
(notif.account.display_name || "@" + notif.account.username) +
(notif.account.display_name ||
"@" + notif.account.username) +
" is now following you.";
break;
case "mention":
primaryMessage =
(notif.account.display_name || "@" + notif.account.username) +
(notif.account.display_name ||
"@" + notif.account.username) +
" mentioned you in a post.";
if (notif.status) {
const div = document.createElement("div");
div.innerHTML = notif.status.content;
secondaryMessage =
(div.textContent || div.innerText || "").slice(0, 100) + "...";
(div.textContent || div.innerText || "").slice(
0,
100
) + "...";
}
break;
case "reblog":
primaryMessage =
(notif.account.display_name || "@" + notif.account.username) +
(notif.account.display_name ||
"@" + notif.account.username) +
" reblogged your post.";
if (notif.status) {
const div = document.createElement("div");
div.innerHTML = notif.status.content;
secondaryMessage =
(div.textContent || div.innerText || "").slice(0, 100) + "...";
(div.textContent || div.innerText || "").slice(
0,
100
) + "...";
}
break;
}
@ -229,15 +246,14 @@ export class AppLayout extends Component<any, IAppLayoutState> {
return (
<div className={classes.titleBarRoot}>
<Typography className={classes.titleBarText}>
{this.state.brandName ? this.state.brandName : "Hyperspace"}{" "}
{this.state.developerMode ? "(beta)" : null}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}{" "}
{this.state.developerMode ? "(Beta)" : null}
</Typography>
</div>
);
} else if (
this.state.developerMode ||
process.env.NODE_ENV === "development"
) {
} else if (process.env.NODE_ENV === "development") {
return (
<div className={classes.titleBarRoot}>
<Typography className={classes.titleBarText}>
@ -258,7 +274,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
button
key="profile-mobile"
to={`/profile/${
this.state.currentUser ? this.state.currentUser.id : "1"
this.state.currentUser
? this.state.currentUser.id
: "1"
}`}
>
<ListItemAvatar>
@ -266,7 +284,8 @@ export class AppLayout extends Component<any, IAppLayoutState> {
alt="You"
src={
this.state.currentUser
? this.state.currentUser.avatar_static
? this.state.currentUser
.avatar_static
: ""
}
/>
@ -326,7 +345,10 @@ export class AppLayout extends Component<any, IAppLayoutState> {
<ListItemIcon>
<PublicIcon />
</ListItemIcon>
<ListItemText primary="Public" secondary="Disabled by admin" />
<ListItemText
primary="Public"
secondary="Disabled by admin"
/>
</ListItem>
)}
<Divider />
@ -351,7 +373,11 @@ export class AppLayout extends Component<any, IAppLayoutState> {
</ListItemIcon>
<ListItemText primary="Notifications" />
</LinkableListItem>
<LinkableListItem button key="messages-mobile" to="/messages">
<LinkableListItem
button
key="messages-mobile"
to="/messages"
>
<ListItemIcon>
<MailIcon />
</ListItemIcon>
@ -360,7 +386,11 @@ export class AppLayout extends Component<any, IAppLayoutState> {
<Divider />
</div>
<ListSubheader>More</ListSubheader>
<LinkableListItem button key="recommended" to="/recommended">
<LinkableListItem
button
key="recommended"
to="/recommended"
>
<ListItemIcon>
<GroupIcon />
</ListItemIcon>
@ -405,7 +435,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
color="inherit"
noWrap
>
{this.state.brandName ? this.state.brandName : "Hyperspace"}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}
</Typography>
<div className={classes.appBarFlexGrow} />
<div className={classes.appBarSearch}>
@ -420,7 +452,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
}}
onKeyUp={event => {
if (event.keyCode === 13) {
this.searchForQuery(event.currentTarget.value);
this.searchForQuery(
event.currentTarget.value
);
}
}}
/>
@ -436,7 +470,8 @@ export class AppLayout extends Component<any, IAppLayoutState> {
<Badge
badgeContent={
this.state.notificationCount > 0
? this.state.notificationCount
? this.state
.notificationCount
: ""
}
color="secondary"
@ -446,18 +481,27 @@ export class AppLayout extends Component<any, IAppLayoutState> {
</LinkableIconButton>
</Tooltip>
<Tooltip title="Direct messages">
<LinkableIconButton color="inherit" to="/messages">
<LinkableIconButton
color="inherit"
to="/messages"
>
<MailIcon />
</LinkableIconButton>
</Tooltip>
<Tooltip title="Your account">
<IconButton id="acctMenuBtn" onClick={this.toggleAcctMenu}>
<IconButton
id="acctMenuBtn"
onClick={this.toggleAcctMenu}
>
<Avatar
className={classes.appBarAcctMenuIcon}
className={
classes.appBarAcctMenuIcon
}
alt="You"
src={
this.state.currentUser
? this.state.currentUser.avatar_static
? this.state.currentUser
.avatar_static
: ""
}
/>
@ -466,16 +510,21 @@ export class AppLayout extends Component<any, IAppLayoutState> {
<Menu
id="acct-menu"
anchorEl={document.getElementById("acctMenuBtn")}
anchorEl={document.getElementById(
"acctMenuBtn"
)}
open={this.state.acctMenuOpen}
className={classes.acctMenu}
>
<ClickAwayListener onClickAway={this.toggleAcctMenu}>
<ClickAwayListener
onClickAway={this.toggleAcctMenu}
>
<div>
<LinkableListItem
to={`/profile/${
this.state.currentUser
? this.state.currentUser.id
? this.state.currentUser
.id
: "1"
}`}
>
@ -483,8 +532,11 @@ export class AppLayout extends Component<any, IAppLayoutState> {
<Avatar
alt="You"
src={
this.state.currentUser
? this.state.currentUser.avatar_static
this.state
.currentUser
? this.state
.currentUser
.avatar_static
: ""
}
/>
@ -492,21 +544,36 @@ export class AppLayout extends Component<any, IAppLayoutState> {
<ListItemText
primary={
this.state.currentUser
? this.state.currentUser.display_name ||
this.state.currentUser.acct
? this.state
.currentUser
.display_name ||
this.state
.currentUser
.acct
: "Loading..."
}
secondary={
"@" +
(this.state.currentUser
? this.state.currentUser.acct
? this.state
.currentUser
.acct
: "Loading...")
}
/>
</LinkableListItem>
<Divider />
<LinkableListItem to={"/you"}>
<ListItemText>
Edit profile
</ListItemText>
</LinkableListItem>
{/* <MenuItem>Switch account</MenuItem> */}
<MenuItem onClick={() => this.toggleLogOutDialog()}>
<MenuItem
onClick={() =>
this.toggleLogOutDialog()
}
>
Log out
</MenuItem>
</div>
@ -549,14 +616,22 @@ export class AppLayout extends Component<any, IAppLayoutState> {
>
<DialogTitle id="alert-dialog-title">
Log out of{" "}
{this.state.brandName ? this.state.brandName : "Hyperspace"}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
You'll need to remove{" "}
{this.state.brandName ? this.state.brandName : "Hyperspace"} from
your list of authorized apps and log in again if you want to use{" "}
{this.state.brandName ? this.state.brandName : "Hyperspace"}.
{this.state.brandName
? this.state.brandName
: "Hyperspace"}{" "}
from your list of authorized apps and log in again
if you want to use{" "}
{this.state.brandName
? this.state.brandName
: "Hyperspace"}
.
</DialogContentText>
</DialogContent>
<DialogActions>

View File

@ -85,7 +85,9 @@ class AttachmentComponent extends Component<
/>
);
case "unknown":
return <object data={slide.url} className={classes.mediaObject} />;
return (
<object data={slide.url} className={classes.mediaObject} />
);
}
}
@ -113,7 +115,10 @@ class AttachmentComponent extends Component<
<Button
size="small"
onClick={() => this.moveForward()}
disabled={this.state.currentStep === this.state.totalSteps - 1}
disabled={
this.state.currentStep ===
this.state.totalSteps - 1
}
>
Next
</Button>

View File

@ -48,7 +48,9 @@ class ComposeMediaAttachment extends Component<
this.props.enqueueSnackbar("Description updated.");
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't update description: " + err.name);
this.props.enqueueSnackbar(
"Couldn't update description: " + err.name
);
});
}
@ -59,7 +61,9 @@ class ComposeMediaAttachment extends Component<
{attachment.type === "image" || attachment.type === "gifv" ? (
<img
src={attachment.url}
alt={attachment.description ? attachment.description : ""}
alt={
attachment.description ? attachment.description : ""
}
/>
) : attachment.type === "video" ? (
<video autoPlay={false} src={attachment.url} />
@ -74,13 +78,19 @@ class ComposeMediaAttachment extends Component<
label="Description"
margin="dense"
className={classes.attachmentText}
onBlur={event => this.updateAttachmentText(event.target.value)}
onBlur={event =>
this.updateAttachmentText(event.target.value)
}
></TextField>
}
actionIcon={
<IconButton
color="inherit"
onClick={() => this.props.onDeleteCallback(this.state.attachment)}
onClick={() =>
this.props.onDeleteCallback(
this.state.attachment
)
}
>
<DeleteIcon />
</IconButton>

View File

@ -106,7 +106,9 @@ export class Post extends React.Component<any, IPostState> {
this.client
.del("/statuses/" + this.state.post.id)
.then((resp: any) => {
this.props.enqueueSnackbar("Post deleted. Refresh to see changes.");
this.props.enqueueSnackbar(
"Post deleted. Refresh to see changes."
);
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't delete post: " + err.name);
@ -193,7 +195,9 @@ export class Post extends React.Component<any, IPostState> {
<div className={classes.mediaContainer}>
<Typography
paragraph
dangerouslySetInnerHTML={{ __html: oldContent.innerHTML }}
dangerouslySetInnerHTML={{
__html: oldContent.innerHTML
}}
/>
{status.card ? (
<div className={classes.postCard}>
@ -204,16 +208,24 @@ export class Post extends React.Component<any, IPostState> {
rel="noreferrer"
>
<CardContent>
<Typography gutterBottom variant="h6" component="h2">
<Typography
gutterBottom
variant="h6"
component="h2"
>
{status.card.title}
</Typography>
<Typography>
{status.card.description.slice(0, 500) +
(status.card.description.length > 500 ? "..." : "") ||
(status.card.description.length >
500
? "..."
: "") ||
"No description provided. Click with caution."}
</Typography>
</CardContent>
{status.card.image && status.media_attachments.length <= 0 ? (
{status.card.image &&
status.media_attachments.length <= 0 ? (
<CardMedia
className={classes.postMedia}
image={status.card.image}
@ -243,22 +255,27 @@ export class Post extends React.Component<any, IPostState> {
status.poll.voted || status.poll.expired ? (
<div>
<Typography variant="caption">
You can't vote on this poll. Below are the results of the
poll.
You can't vote on this poll. Below are the
results of the poll.
</Typography>
<RadioGroup value={this.findBiggestVote()}>
{status.poll.options.map((pollOption: PollOption) => {
{status.poll.options.map(
(pollOption: PollOption) => {
let x = (
<FormControlLabel
disabled
value={pollOption.title}
control={<Radio />}
label={`${pollOption.title} (${pollOption.votes_count} votes)`}
key={pollOption.title + pollOption.votes_count}
key={
pollOption.title +
pollOption.votes_count
}
/>
);
return x;
})}
}
)}
</RadioGroup>
{status.poll && status.poll.expired ? (
<Typography variant="caption">
@ -268,7 +285,9 @@ export class Post extends React.Component<any, IPostState> {
<Typography variant="caption">
This poll will expire on{" "}
{moment(
status.poll.expires_at ? status.poll.expires_at : ""
status.poll.expires_at
? status.poll.expires_at
: ""
).format("MMMM Do YYYY, [at] h:mm A")}
.
</Typography>
@ -281,17 +300,22 @@ export class Post extends React.Component<any, IPostState> {
this.captureVote(option)
}
>
{status.poll.options.map((pollOption: PollOption) => {
{status.poll.options.map(
(pollOption: PollOption) => {
let x = (
<FormControlLabel
value={pollOption.title}
control={<Radio />}
label={pollOption.title}
key={pollOption.title + pollOption.votes_count}
key={
pollOption.title +
pollOption.votes_count
}
/>
);
return x;
})}
}
)}
</RadioGroup>
<Button
color="primary"
@ -338,11 +362,17 @@ export class Post extends React.Component<any, IPostState> {
}
color="inherit"
>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />} color="inherit">
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
color="inherit"
>
{icon}
<Typography>{warningText}</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails className={classes.postContent} color="inherit">
<ExpansionPanelDetails
className={classes.postContent}
color="inherit"
>
{this.materializeContent(content)}
</ExpansionPanelDetails>
</ExpansionPanel>
@ -364,18 +394,21 @@ export class Post extends React.Component<any, IPostState> {
const { classes } = this.props;
if (post.reblog) {
let author = post.reblog.account;
let origString = `<span>${author.display_name || author.username} (@${
author.acct
}) 🔄 ${post.account.display_name || post.account.username}</span>`;
let origString = `<span>${author.display_name ||
author.username} (@${author.acct}) 🔄 ${post.account
.display_name || post.account.username}</span>`;
let emojis = author.emojis;
emojis.concat(post.account.emojis);
return emojifyString(origString, emojis, classes.postAuthorEmoji);
} else {
let author = post.account;
let origString = `<span>${author.display_name || author.username} (@${
author.acct
})</span>`;
return emojifyString(origString, author.emojis, classes.postAuthorEmoji);
let origString = `<span>${author.display_name ||
author.username} (@${author.acct})</span>`;
return emojifyString(
origString,
author.emojis,
classes.postAuthorEmoji
);
}
}
@ -394,7 +427,9 @@ export class Post extends React.Component<any, IPostState> {
</Avatar>
}
label={person.username}
key={this.state.post.id + "_mention_" + person.id}
key={
this.state.post.id + "_mention_" + person.id
}
to={`/profile/${person.id}`}
className={classes.postMention}
clickable
@ -481,9 +516,12 @@ export class Post extends React.Component<any, IPostState> {
this.setState({ post });
})
.catch((err: Error) => {
_this.props.enqueueSnackbar(`Couldn't unfavorite post: ${err.name}`, {
_this.props.enqueueSnackbar(
`Couldn't unfavorite post: ${err.name}`,
{
variant: "error"
});
}
);
console.log(err.message);
});
} else {
@ -494,9 +532,12 @@ export class Post extends React.Component<any, IPostState> {
this.setState({ post });
})
.catch((err: Error) => {
_this.props.enqueueSnackbar(`Couldn't favorite post: ${err.name}`, {
_this.props.enqueueSnackbar(
`Couldn't favorite post: ${err.name}`,
{
variant: "error"
});
}
);
console.log(err.message);
});
}
@ -511,9 +552,12 @@ export class Post extends React.Component<any, IPostState> {
this.setState({ post });
})
.catch((err: Error) => {
this.props.enqueueSnackbar(`Couldn't unboost post: ${err.name}`, {
this.props.enqueueSnackbar(
`Couldn't unboost post: ${err.name}`,
{
variant: "error"
});
}
);
console.log(err.message);
});
} else {
@ -524,9 +568,12 @@ export class Post extends React.Component<any, IPostState> {
this.setState({ post });
})
.catch((err: Error) => {
this.props.enqueueSnackbar(`Couldn't boost post: ${err.name}`, {
this.props.enqueueSnackbar(
`Couldn't boost post: ${err.name}`,
{
variant: "error"
});
}
);
console.log(err.message);
});
}
@ -538,11 +585,13 @@ export class Post extends React.Component<any, IPostState> {
open={this.state.deletePostDialog}
onClose={() => this.togglePostDeleteDialog()}
>
<DialogTitle id="alert-dialog-title">Delete this post?</DialogTitle>
<DialogTitle id="alert-dialog-title">
Delete this post?
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete this post? This action cannot be
undone.
Are you sure you want to delete this post? This action
cannot be undone.
</DialogContentText>
</DialogContent>
<DialogActions>
@ -577,7 +626,9 @@ export class Post extends React.Component<any, IPostState> {
avatar={
<LinkableAvatar
to={`/profile/${
post.reblog ? post.reblog.account.id : post.account.id
post.reblog
? post.reblog.account.id
: post.account.id
}`}
src={
post.reblog
@ -626,17 +677,23 @@ export class Post extends React.Component<any, IPostState> {
to={`/compose?reply=${
post.reblog ? post.reblog.id : post.id
}&visibility=${post.visibility}&acct=${
post.reblog ? post.reblog.account.acct : post.account.acct
post.reblog
? post.reblog.account.acct
: post.account.acct
}`}
>
<ReplyIcon />
</LinkableIconButton>
</Tooltip>
<Typography>
{post.reblog ? post.reblog.replies_count : post.replies_count}
{post.reblog
? post.reblog.replies_count
: post.replies_count}
</Typography>
<Tooltip title="Favorite">
<IconButton onClick={() => this.toggleFavorited(post)}>
<IconButton
onClick={() => this.toggleFavorited(post)}
>
<FavoriteIcon
className={
post.reblog
@ -656,7 +713,9 @@ export class Post extends React.Component<any, IPostState> {
: post.favourites_count}
</Typography>
<Tooltip title="Boost">
<IconButton onClick={() => this.toggleReblogged(post)}>
<IconButton
onClick={() => this.toggleReblogged(post)}
>
<AutorenewIcon
className={
post.reblog
@ -671,16 +730,26 @@ export class Post extends React.Component<any, IPostState> {
</IconButton>
</Tooltip>
<Typography>
{post.reblog ? post.reblog.reblogs_count : post.reblogs_count}
{post.reblog
? post.reblog.reblogs_count
: post.reblogs_count}
</Typography>
<Tooltip className={classes.desktopOnly} title="View thread">
<Tooltip
className={classes.desktopOnly}
title="View thread"
>
<LinkableIconButton
to={`/conversation/${post.reblog ? post.reblog.id : post.id}`}
to={`/conversation/${
post.reblog ? post.reblog.id : post.id
}`}
>
<ForumIcon />
</LinkableIconButton>
</Tooltip>
<Tooltip className={classes.desktopOnly} title="Open in Web">
<Tooltip
className={classes.desktopOnly}
title="Open in Web"
>
<IconButton
href={this.getMastodonUrl(post)}
rel="noreferrer"
@ -722,22 +791,30 @@ export class Post extends React.Component<any, IPostState> {
/>
{post.reblog ? (
<div>
<LinkableMenuItem to={`/profile/${post.reblog.account.id}`}>
<LinkableMenuItem
to={`/profile/${post.reblog.account.id}`}
>
View author profile
</LinkableMenuItem>
<LinkableMenuItem to={`/profile/${post.account.id}`}>
<LinkableMenuItem
to={`/profile/${post.account.id}`}
>
View reblogger profile
</LinkableMenuItem>
</div>
) : (
<LinkableMenuItem to={`/profile/${post.account.id}`}>
<LinkableMenuItem
to={`/profile/${post.account.id}`}
>
View profile
</LinkableMenuItem>
)}
<div className={classes.mobileOnly}>
<Divider />
<LinkableMenuItem
to={`/conversation/${post.reblog ? post.reblog.id : post.id}`}
to={`/conversation/${
post.reblog ? post.reblog.id : post.id
}`}
>
View thread
</LinkableMenuItem>
@ -751,10 +828,15 @@ export class Post extends React.Component<any, IPostState> {
</MenuItem>
</div>
{post.account.id ==
JSON.parse(localStorage.getItem("account") as string).id ? (
JSON.parse(localStorage.getItem("account") as string)
.id ? (
<div>
<Divider />
<MenuItem onClick={() => this.togglePostDeleteDialog()}>
<MenuItem
onClick={() =>
this.togglePostDeleteDialog()
}
>
Delete
</MenuItem>
</div>

View File

@ -37,7 +37,9 @@ class ThemePreview extends Component<IThemePreviewProps, IThemePreviewState> {
<Paper>
<AppBar color="primary" position="static">
<Toolbar>
<MenuIcon style={{ marginRight: 20, marginLeft: -4 }} />
<MenuIcon
style={{ marginRight: 20, marginLeft: -4 }}
/>
<Typography variant="h6" color="inherit">
Hyperspace
</Typography>
@ -57,17 +59,20 @@ class ThemePreview extends Component<IThemePreviewProps, IThemePreviewState> {
</Typography>
<br />
<Typography paragraph>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
vestibulum congue sem ac ornare. In nec imperdiet neque. In
eleifend laoreet efficitur. Vestibulum vel odio mattis,
scelerisque nibh a, ornare lectus. Phasellus sollicitudin erat
et turpis pellentesque consequat. In maximus luctus purus, eu
molestie elit euismod eu. Pellentesque quam lectus, sagittis
eget accumsan in, consequat ut sapien. Morbi aliquet ligula
erat, id dapibus nunc laoreet at. Integer sodales lacinia
finibus. Aliquam augue nibh, eleifend quis consectetur et,
rhoncus ut odio. Lorem ipsum dolor sit amet, consectetur
adipiscing elit.
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Nunc vestibulum congue sem ac
ornare. In nec imperdiet neque. In eleifend
laoreet efficitur. Vestibulum vel odio mattis,
scelerisque nibh a, ornare lectus. Phasellus
sollicitudin erat et turpis pellentesque
consequat. In maximus luctus purus, eu molestie
elit euismod eu. Pellentesque quam lectus,
sagittis eget accumsan in, consequat ut sapien.
Morbi aliquet ligula erat, id dapibus nunc
laoreet at. Integer sodales lacinia finibus.
Aliquam augue nibh, eleifend quis consectetur
et, rhoncus ut odio. Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
</Typography>
</div>
<div style={{ textAlign: "right" }}>

View File

@ -110,6 +110,135 @@ class AboutPage extends Component<any, IAboutPageState> {
return (
<div className={classes.pageLayoutConstraints}>
<Paper>
<div
className={classes.instanceHeaderPaper}
style={{
backgroundImage: `url("${
this.state.brandBg ? this.state.brandBg : ""
}")`
}}
>
<div className={classes.instanceToolbar}>
{this.state.repository ? (
<Tooltip title="View source code">
<IconButton
href={this.state.repository}
target="_blank"
rel="noreferrer"
color="inherit"
>
<CodeIcon />
</IconButton>
</Tooltip>
) : null}
</div>
<div className={classes.instanceHeaderText}>
<Typography variant="h4" component="p">
{this.state.brandName? this.state.brandName: "Hyperspace"}
</Typography>
<Typography>Version {`${this.state? this.state.versionNumber: "1.0.x"} ${this.state && this.state.brandName !== "Hyperspace"? "(Hyperspace-like)": ""}`}</Typography>
</div>
</div>
<List className={classes.pageListConstraints}>
<ListItem>
<ListItemAvatar>
<LinkableAvatar
to={`/profile/${
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.id
: 0
}`}
src={
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.avatar_static
: ""
}
>
<PersonIcon />
</LinkableAvatar>
</ListItemAvatar>
<ListItemText
primary="App provider"
secondary={
this.state.hyperspaceAdmin && this.state.hyperspaceAdminName
? this.state.hyperspaceAdminName ||
this.state.hyperspaceAdmin.display_name ||
"@" + this.state.hyperspaceAdmin.acct
: "No provider set in config"
}
/>
<ListItemSecondaryAction>
<Tooltip title="Send a post or message">
<LinkableIconButton
to={`/compose?visibility=${
this.state.federated ? "public" : "private"
}&acct=${
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.acct
: ""
}`}
>
<ChatIcon />
</LinkableIconButton>
</Tooltip>
<Tooltip title="View profile">
<LinkableIconButton
to={`/profile/${
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.id
: 0
}`}
>
<AssignmentIndIcon />
</LinkableIconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<NotesIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="License"
secondary={this.state.license.name}
/>
<ListItemSecondaryAction>
<Tooltip title="View license">
<IconButton
href={this.state.license.url}
target="_blank"
rel="noreferrer"
>
<OpenInNewIcon />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<UpdateIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Release channel"
secondary={
this.state
? this.state.developer
? "Developer"
: "Release"
: "Loading..."
}
/>
</ListItem>
</List>
</Paper>
<br />
<Paper>
<div
className={classes.instanceHeaderPaper}
@ -130,13 +259,10 @@ class AboutPage extends Component<any, IAboutPageState> {
>
<OpenInNewIcon />
</IconButton>
<Typography
className={classes.instanceHeaderText}
variant="h4"
component="p"
>
{this.state.instance ? this.state.instance.uri : "Loading..."}
</Typography>
<div className={classes.instanceHeaderText}>
<Typography variant="h4" component="p">{this.state.instance ? this.state.instance.uri: "Loading..."}</Typography>
<Typography>Server version {this.state.instance? this.state.instance.version: "x.x.x"}</Typography>
</div>
</div>
<List className={classes.pageListConstraints}>
{localStorage["isPleroma"] == "false" && (
@ -238,168 +364,9 @@ class AboutPage extends Component<any, IAboutPageState> {
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<MastodonIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Mastodon version"
secondary={
this.state.instance ? this.state.instance.version : "x.x.x"
}
/>
</ListItem>
</List>
</Paper>
<br />
<Paper>
<div
className={classes.instanceHeaderPaper}
style={{
backgroundImage: `url("${
this.state.brandBg ? this.state.brandBg : ""
}")`
}}
>
<div className={classes.instanceToolbar}>
{this.state.repository ? (
<Tooltip title="View source code">
<IconButton
href={this.state.repository}
target="_blank"
rel="noreferrer"
color="inherit"
>
<CodeIcon />
</IconButton>
</Tooltip>
) : null}
</div>
<Typography
className={classes.instanceHeaderText}
variant="h4"
component="p"
>
{this.state.brandName ? this.state.brandName : "Hyperspace"}
</Typography>
</div>
<List className={classes.pageListConstraints}>
<ListItem>
<ListItemAvatar>
<LinkableAvatar
to={`/profile/${
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.id
: 0
}`}
src={
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.avatar_static
: ""
}
>
<PersonIcon />
</LinkableAvatar>
</ListItemAvatar>
<ListItemText
primary="App provider"
secondary={
this.state.hyperspaceAdmin && this.state.hyperspaceAdminName
? this.state.hyperspaceAdminName ||
this.state.hyperspaceAdmin.display_name ||
"@" + this.state.hyperspaceAdmin.acct
: "No provider set in config"
}
/>
<ListItemSecondaryAction>
<Tooltip title="Send a post or message">
<LinkableIconButton
to={`/compose?visibility=${
this.state.federated ? "public" : "private"
}&acct=${
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.acct
: ""
}`}
>
<ChatIcon />
</LinkableIconButton>
</Tooltip>
<Tooltip title="View profile">
<LinkableIconButton
to={`/profile/${
this.state.hyperspaceAdmin
? this.state.hyperspaceAdmin.id
: 0
}`}
>
<AssignmentIndIcon />
</LinkableIconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<NotesIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="License"
secondary={this.state.license.name}
/>
<ListItemSecondaryAction>
<Tooltip title="View license">
<IconButton
href={this.state.license.url}
target="_blank"
rel="noreferrer"
>
<OpenInNewIcon />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<UpdateIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Release channel"
secondary={
this.state
? this.state.developer
? "Developer"
: "Release"
: "Loading..."
}
/>
</ListItem>
<ListItem>
<ListItemAvatar>
<Avatar>
<InfoIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="App version"
secondary={`${
this.state ? this.state.brandName : "Hyperspace"
} v${this.state ? this.state.versionNumber : "1.0.x"} ${
this.state && this.state.brandName !== "Hyperspace"
? "(Hyperspace-like)"
: ""
}`}
/>
</ListItem>
</List>
</Paper>
<br />
<ListSubheader>Federation status</ListSubheader>
<Paper>

View File

@ -180,9 +180,10 @@ class Composer extends Component<any, IComposerState> {
})
.catch((err: Error) => {
this.props.closeSnackbar("media-upload");
this.props.enqueueSnackbar("Couldn't upload media: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't upload media: " + err.name,
{ variant: "error" }
);
});
})
.catch((err: Error) => {
@ -249,7 +250,8 @@ class Composer extends Component<any, IComposerState> {
let expiration = new Date();
let current = new Date();
expiration.setMinutes(expiration.getMinutes() + 30);
let expiryDifference = expiration.getTime() - current.getTime() / 1000;
let expiryDifference =
expiration.getTime() - current.getTime() / 1000;
let temporaryPoll: PollWizard = {
expires_at: expiryDifference.toString(),
multiple: false,
@ -263,7 +265,10 @@ class Composer extends Component<any, IComposerState> {
}
addPollItem() {
if (this.state.poll !== undefined && this.state.poll.options.length < 4) {
if (
this.state.poll !== undefined &&
this.state.poll.options.length < 4
) {
let newOption = { title: "New option" };
let options = this.state.poll.options;
let poll = this.state.poll;
@ -299,7 +304,10 @@ class Composer extends Component<any, IComposerState> {
}
removePollItem(item: string) {
if (this.state.poll !== undefined && this.state.poll.options.length > 2) {
if (
this.state.poll !== undefined &&
this.state.poll.options.length > 2
) {
let options = this.state.poll.options;
let poll = this.state.poll;
options.forEach((option: PollWizardOption) => {
@ -427,16 +435,18 @@ class Composer extends Component<any, IComposerState> {
label="Content warning"
margin="dense"
onChange={event =>
this.updateWarningFromField(event.target.value)
this.updateWarningFromField(
event.target.value
)
}
></TextField>
</Fade>
) : null}
{this.state.visibility === "direct" ? (
<Typography variant="caption">
<WarningIcon className={classes.warningCaption} /> Don't forget to
add the usernames of the accounts you want to message in your
post.
<WarningIcon className={classes.warningCaption} />{" "}
Don't forget to add the usernames of the accounts
you want to message in your post.
</Typography>
) : null}
@ -446,7 +456,9 @@ class Composer extends Component<any, IComposerState> {
fullWidth
placeholder="What's on your mind?"
margin="normal"
onChange={event => this.updateTextFromField(event.target.value)}
onChange={event =>
this.updateTextFromField(event.target.value)
}
onKeyDown={event => this.postViaKeyboard(event)}
inputProps={{
maxLength: 500
@ -465,11 +477,14 @@ class Composer extends Component<any, IComposerState> {
this.state.remainingChars === 1 ? "" : "s"
} remaining`}
</Typography>
{this.state.attachments && this.state.attachments.length > 0 ? (
{this.state.attachments &&
this.state.attachments.length > 0 ? (
<div className={classes.composeAttachmentArea}>
<GridList
cellHeight={48}
className={classes.composeAttachmentAreaGridList}
className={
classes.composeAttachmentAreaGridList
}
>
<GridListTile
key="Subheader-composer"
@ -478,21 +493,31 @@ class Composer extends Component<any, IComposerState> {
>
<ListSubheader>Attachments</ListSubheader>
</GridListTile>
{this.state.attachments.map((attachment: Attachment) => {
{this.state.attachments.map(
(attachment: Attachment) => {
let c = (
<ComposeMediaAttachment
client={this.client}
attachment={attachment}
onAttachmentUpdate={(attachment: Attachment) =>
this.fetchAttachmentAfterUpdate(attachment)
onAttachmentUpdate={(
attachment: Attachment
) =>
this.fetchAttachmentAfterUpdate(
attachment
)
}
onDeleteCallback={(attachment: Attachment) =>
this.deleteMediaAttachment(attachment)
onDeleteCallback={(
attachment: Attachment
) =>
this.deleteMediaAttachment(
attachment
)
}
/>
);
return c;
})}
}
)}
</GridList>
</div>
) : null}
@ -500,25 +525,46 @@ class Composer extends Component<any, IComposerState> {
<div style={{ marginTop: 4 }}>
{this.state.poll
? this.state.poll.options.map(
(option: PollWizardOption, index: number) => {
(
option: PollWizardOption,
index: number
) => {
let c = (
<div
style={{ display: "flex" }}
key={"compose_option_" + index.toString()}
key={
"compose_option_" +
index.toString()
}
>
<RadioButtonCheckedIcon
className={classes.pollWizardOptionIcon}
className={
classes.pollWizardOptionIcon
}
/>
<TextField
onBlur={(event: any) =>
this.editPollItem(index, event)
this.editPollItem(
index,
event
)
}
defaultValue={
option.title
}
/>
<div
className={
classes.pollWizardFlexGrow
}
defaultValue={option.title}
/>
<div className={classes.pollWizardFlexGrow} />
<Tooltip title="Remove poll option">
<IconButton
onClick={() => this.removePollItem(option.title)}
onClick={() =>
this.removePollItem(
option.title
)
}
>
<DeleteIcon />
</IconButton>
@ -538,14 +584,18 @@ class Composer extends Component<any, IComposerState> {
: new Date()
}
onChange={(date: any) => {
this.setPollExpires(date.toISOString());
this.setPollExpires(
date.toISOString()
);
}}
label="Poll exipres on"
disablePast
/>
</MuiPickersUtilsProvider>
<div className={classes.pollWizardFlexGrow} />
<Button onClick={() => this.addPollItem()}>Add Option</Button>
<Button onClick={() => this.addPollItem()}>
Add Option
</Button>
</div>
</div>
) : null}
@ -575,16 +625,21 @@ class Composer extends Component<any, IComposerState> {
onClose={() => this.toggleEmojis()}
className={classes.composeEmoji}
>
<EmojiPicker onGetEmoji={(emoji: any) => this.insertEmoji(emoji)} />
<EmojiPicker
onGetEmoji={(emoji: any) => this.insertEmoji(emoji)}
/>
</Menu>
<Tooltip title="Add/remove a poll">
<IconButton
disabled={
this.state.attachments && this.state.attachments.length > 0
this.state.attachments &&
this.state.attachments.length > 0
}
id="compose-poll"
onClick={() => {
this.state.poll ? this.removePoll() : this.createPoll();
this.state.poll
? this.removePoll()
: this.createPoll();
}}
>
<HowToVoteIcon />
@ -611,17 +666,25 @@ class Composer extends Component<any, IComposerState> {
anchorEl={document.getElementById("compose-visibility")}
onClose={() => this.toggleVisibilityMenu()}
>
<MenuItem onClick={() => this.changeVisibility("direct")}>
<MenuItem
onClick={() => this.changeVisibility("direct")}
>
Direct (direct message)
</MenuItem>
<MenuItem onClick={() => this.changeVisibility("private")}>
<MenuItem
onClick={() => this.changeVisibility("private")}
>
Private (followers only)
</MenuItem>
<MenuItem onClick={() => this.changeVisibility("unlisted")}>
<MenuItem
onClick={() => this.changeVisibility("unlisted")}
>
Unlisted
</MenuItem>
{this.state.federated ? (
<MenuItem onClick={() => this.changeVisibility("public")}>
<MenuItem
onClick={() => this.changeVisibility("public")}
>
Public
</MenuItem>
) : null}

View File

@ -52,9 +52,10 @@ class Conversation extends Component<any, IConversationPageState> {
viewDidError: true,
viewDidErrorCode: err.message
});
this.props.enqueueSnackbar("Couldn't get conversation: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't get conversation: " + err.name,
{ variant: "error" }
);
});
this.client
.get(`/statuses/${this.state.conversationId}/context`)
@ -81,9 +82,10 @@ class Conversation extends Component<any, IConversationPageState> {
viewDidError: true,
viewDidErrorCode: err.message
});
this.props.enqueueSnackbar("Couldn't get conversation: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't get conversation: " + err.name,
{ variant: "error" }
);
});
}
@ -117,7 +119,13 @@ class Conversation extends Component<any, IConversationPageState> {
{this.state.posts ? (
<div>
{this.state.posts.map((post: Status) => {
return <Post key={post.id} post={post} client={this.client} />;
return (
<Post
key={post.id}
post={post}
client={this.client}
/>
);
})}
</div>
) : (
@ -130,7 +138,9 @@ class Conversation extends Component<any, IConversationPageState> {
Something went wrong when loading this conversation.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -138,7 +148,10 @@ class Conversation extends Component<any, IConversationPageState> {
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />

View File

@ -167,8 +167,12 @@ class HomePage extends Component<any, IHomePageState> {
<ArrowUpwardIcon />
</Avatar>
}
label={`View ${this.state.backlogPosts.length} new post${
this.state.backlogPosts.length > 1 ? "s" : ""
label={`View ${
this.state.backlogPosts.length
} new post${
this.state.backlogPosts.length > 1
? "s"
: ""
}`}
color="primary"
className={classes.pageTopChip}
@ -182,7 +186,13 @@ class HomePage extends Component<any, IHomePageState> {
{this.state.posts ? (
<div>
{this.state.posts.map((post: Status) => {
return <Post key={post.id} post={post} client={this.client} />;
return (
<Post
key={post.id}
post={post}
client={this.client}
/>
);
})}
<br />
{this.state.viewDidLoad && !this.state.viewDidError ? (
@ -204,7 +214,9 @@ class HomePage extends Component<any, IHomePageState> {
Something went wrong when loading this timeline.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -212,7 +224,10 @@ class HomePage extends Component<any, IHomePageState> {
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />

View File

@ -168,8 +168,12 @@ class LocalPage extends Component<any, ILocalPageState> {
<ArrowUpwardIcon />
</Avatar>
}
label={`View ${this.state.backlogPosts.length} new post${
this.state.backlogPosts.length > 1 ? "s" : ""
label={`View ${
this.state.backlogPosts.length
} new post${
this.state.backlogPosts.length > 1
? "s"
: ""
}`}
color="primary"
className={classes.pageTopChip}
@ -183,7 +187,13 @@ class LocalPage extends Component<any, ILocalPageState> {
{this.state.posts ? (
<div>
{this.state.posts.map((post: Status) => {
return <Post key={post.id} post={post} client={this.client} />;
return (
<Post
key={post.id}
post={post}
client={this.client}
/>
);
})}
<br />
{this.state.viewDidLoad && !this.state.viewDidError ? (
@ -205,7 +215,9 @@ class LocalPage extends Component<any, ILocalPageState> {
Something went wrong when loading this timeline.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -213,7 +225,10 @@ class LocalPage extends Component<any, ILocalPageState> {
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />

View File

@ -80,24 +80,39 @@ class MessagesPage extends Component<any, IMessagesState> {
<Paper className={classes.pageListConstraints}>
<List>
{this.state.posts
? this.state.posts.map((message: Status) => {
? this.state.posts.map(
(message: Status) => {
return (
<ListItem>
<ListItemAvatar>
<LinkableAvatar
to={`/profile/${message.account.id}`}
alt={message.account.username}
src={message.account.avatar_static}
alt={
message
.account
.username
}
src={
message
.account
.avatar_static
}
>
<PersonIcon />
</LinkableAvatar>
</ListItemAvatar>
<ListItemText
primary={
message.account.display_name ||
"@" + message.account.acct
message.account
.display_name ||
"@" +
message
.account
.acct
}
secondary={this.removeHTMLContent(message.content)}
secondary={this.removeHTMLContent(
message.content
)}
/>
<ListItemSecondaryAction>
<Tooltip title="View conversation">
@ -110,7 +125,8 @@ class MessagesPage extends Component<any, IMessagesState> {
</ListItemSecondaryAction>
</ListItem>
);
})
}
)
: null}
</List>
</Paper>
@ -119,7 +135,10 @@ class MessagesPage extends Component<any, IMessagesState> {
) : null}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : null}
</div>

View File

@ -16,7 +16,11 @@ class Missingno extends Component<any, any> {
The part of Hyperspace you're looking for isn't here.
</Typography>
<br />
<LinkableButton to="/home" color="primary" variant="contained">
<LinkableButton
to="/home"
color="primary"
variant="contained"
>
Go back to home timeline
</LinkableButton>
</div>

View File

@ -115,8 +115,14 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
let notifications = this.state.notifications;
if (notifications !== undefined && notifications.length > 0) {
notifications.forEach((notification: Notification) => {
if (notifications !== undefined && notification.id === id) {
notifications.splice(notifications.indexOf(notification), 1);
if (
notifications !== undefined &&
notification.id === id
) {
notifications.splice(
notifications.indexOf(notification),
1
);
}
});
}
@ -206,10 +212,16 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
primary={primary}
secondary={
<span>
<Typography color="textSecondary" className={classes.mobileOnly}>
<Typography
color="textSecondary"
className={classes.mobileOnly}
>
{secondary.slice(0, 35) + "..."}
</Typography>
<Typography color="textSecondary" className={classes.desktopOnly}>
<Typography
color="textSecondary"
className={classes.desktopOnly}
>
{secondary}
</Typography>
</span>
@ -219,12 +231,18 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
{notif.type === "follow" ? (
<span>
<Tooltip title="View profile">
<LinkableIconButton to={`/profile/${notif.account.id}`}>
<LinkableIconButton
to={`/profile/${notif.account.id}`}
>
<AssignmentIndIcon />
</LinkableIconButton>
</Tooltip>
<Tooltip title="Follow account">
<IconButton onClick={() => this.followMember(notif.account)}>
<IconButton
onClick={() =>
this.followMember(notif.account)
}
>
<PersonAddIcon />
</IconButton>
</Tooltip>
@ -232,7 +250,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
) : notif.status ? (
<span>
<Tooltip title="View conversation">
<LinkableIconButton to={`/conversation/${notif.status.id}`}>
<LinkableIconButton
to={`/conversation/${notif.status.id}`}
>
<ForumIcon />
</LinkableIconButton>
</Tooltip>
@ -243,9 +263,12 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
notif.status.reblog
? notif.status.reblog.id
: notif.status.id
}&visibility=${notif.status.visibility}&acct=${
}&visibility=${
notif.status.visibility
}&acct=${
notif.status.reblog
? notif.status.reblog.account.acct
? notif.status.reblog.account
.acct
: notif.status.account.acct
}`}
>
@ -256,7 +279,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
</span>
) : null}
<Tooltip title="Remove notification">
<IconButton onClick={() => this.removeNotification(notif.id)}>
<IconButton
onClick={() => this.removeNotification(notif.id)}
>
<DeleteIcon />
</IconButton>
</Tooltip>
@ -269,12 +294,15 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
this.client
.post(`/accounts/${acct.id}/follow`)
.then((resp: any) => {
this.props.enqueueSnackbar("You are now following this account.");
this.props.enqueueSnackbar(
"You are now following this account."
);
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't follow account: " + err.name,
{ variant: "error" }
);
console.error(err.message);
});
}
@ -284,7 +312,8 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
return (
<div className={classes.pageLayoutConstraints}>
{this.state.viewDidLoad ? (
this.state.notifications && this.state.notifications.length > 0 ? (
this.state.notifications &&
this.state.notifications.length > 0 ? (
<div>
<ListSubheader>Recent notifications</ListSubheader>
<Button
@ -299,7 +328,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
<List>
{this.state.notifications.map(
(notification: Notification) => {
return this.createNotification(notification);
return this.createNotification(
notification
);
}
)}
</List>
@ -309,8 +340,8 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
<div className={classes.pageLayoutEmptyTextConstraints}>
<Typography variant="h4">All clear!</Typography>
<Typography paragraph>
It looks like you have no notifications. Why not get the
conversation going with a new post?
It looks like you have no notifications. Why not
get the conversation going with a new post?
</Typography>
</div>
)
@ -322,7 +353,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
Something went wrong when loading this timeline.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -330,7 +363,10 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />
@ -345,8 +381,8 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete all notifications? This action
cannot be undone.
Are you sure you want to delete all notifications?
This action cannot be undone.
</DialogContentText>
</DialogContent>
<DialogActions>

View File

@ -90,7 +90,6 @@ export const styles = (theme: Theme) =>
pageHeroContent: {
padding: 16,
paddingTop: 8,
textAlign: "center",
width: "100%",
height: "100%",
[theme.breakpoints.up("md")]: {
@ -254,7 +253,7 @@ export const styles = (theme: Theme) =>
height: 128
},
instanceHeaderPaper: {
height: 200,
height: 150,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
@ -267,9 +266,11 @@ export const styles = (theme: Theme) =>
position: "absolute",
bottom: theme.spacing.unit,
left: theme.spacing.unit * 2,
"& *": {
color: theme.palette.common.white,
textShadow: `0 0 4px ${theme.palette.grey[700]}`,
fontWeight: 600
}
},
instanceToolbar: {
position: "absolute",

View File

@ -135,7 +135,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
getRelationships() {
this.client
.get("/accounts/relationships", { id: this.props.match.params.profileId })
.get("/accounts/relationships", {
id: this.props.match.params.profileId
})
.then((resp: any) => {
let relationship: Relationship = resp.data[0];
this.setState({ relationship });
@ -189,7 +191,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
});
});
} else {
this.props.enqueueSnackbar("Reached end of posts", { variant: "error" });
this.props.enqueueSnackbar("Reached end of posts", {
variant: "error"
});
this.setState({
viewIsLoading: false,
viewDidLoad: true
@ -234,12 +238,15 @@ class ProfilePage extends Component<any, IProfilePageState> {
.then((resp: any) => {
let relationship: Relationship = resp.data;
this.setState({ relationship });
this.props.enqueueSnackbar("You are now following this account.");
this.props.enqueueSnackbar(
"You are now following this account."
);
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't follow account: " + err.name,
{ variant: "error" }
);
console.error(err.message);
});
}
@ -283,12 +290,15 @@ class ProfilePage extends Component<any, IProfilePageState> {
.then((resp: any) => {
let relationship: Relationship = resp.data;
this.setState({ relationship });
this.props.enqueueSnackbar("You are now blocking this account.");
this.props.enqueueSnackbar(
"You are now blocking this account."
);
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't block account: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't block account: " + err.name,
{ variant: "error" }
);
console.error(err.message);
});
}
@ -314,7 +324,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
title={
this.isItMe()
? "You can't follow yourself."
: this.state.relationship && this.state.relationship.following
: this.state.relationship &&
this.state.relationship.following
? "Unfollow"
: "Follow"
}
@ -337,7 +348,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
<Tooltip title={"Send a message or post"}>
<LinkableIconButton
to={`/compose?acct=${
this.state.account ? this.state.account.acct : ""
this.state.account
? this.state.account.acct
: ""
}`}
color={"inherit"}
>
@ -346,7 +359,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
</Tooltip>
<Tooltip
title={
this.state.relationship && this.state.relationship.blocking
this.state.relationship &&
this.state.relationship.blocking
? "Unblock this account"
: "Block this account"
}
@ -356,7 +370,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
disabled={this.isItMe()}
onClick={() => this.toggleBlockDialog()}
>
{this.state.relationship && this.state.relationship.blocking ? (
{this.state.relationship &&
this.state.relationship.blocking ? (
<AccountHeartIcon />
) : (
<AccountRemoveIcon />
@ -365,7 +380,11 @@ class ProfilePage extends Component<any, IProfilePageState> {
</Tooltip>
<Tooltip title="Open in web">
<IconButton
href={this.state.account ? this.state.account.url : ""}
href={
this.state.account
? this.state.account.url
: ""
}
target="_blank"
rel={"nofollower noreferrer noopener"}
color={"inherit"}
@ -384,7 +403,11 @@ class ProfilePage extends Component<any, IProfilePageState> {
<div className={classes.profileContent}>
<Avatar
className={classes.profileAvatar}
src={this.state.account ? this.state.account.avatar : ""}
src={
this.state.account
? this.state.account.avatar
: ""
}
/>
<div className={classes.profileUserBox}>
<Typography
@ -394,7 +417,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
__html: this.state.account
? this.state.account.display_name
? emojifyString(
this.state.account.display_name,
this.state.account
.display_name,
this.state.account.emojis,
classes.pageProfileNameEmoji
)
@ -404,7 +428,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
className={classes.pageProfileNameEmoji}
/>
<Typography variant="caption" color="inherit">
{this.state.account ? "@" + this.state.account.acct : ""}
{this.state.account
? "@" + this.state.account.acct
: ""}
</Typography>
<Typography paragraph color="inherit">
{this.state.account
@ -414,11 +440,17 @@ class ProfilePage extends Component<any, IProfilePageState> {
: "No bio available."}
</Typography>
<Typography color={"inherit"}>
{this.state.account ? this.state.account.followers_count : 0}{" "}
{this.state.account
? this.state.account.followers_count
: 0}{" "}
followers |{" "}
{this.state.account ? this.state.account.following_count : 0}{" "}
{this.state.account
? this.state.account.following_count
: 0}{" "}
following |{" "}
{this.state.account ? this.state.account.statuses_count : 0}{" "}
{this.state.account
? this.state.account.statuses_count
: 0}{" "}
posts
</Typography>
</div>
@ -432,7 +464,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
Something went wrong when loading this profile.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -441,15 +475,26 @@ class ProfilePage extends Component<any, IProfilePageState> {
{this.state.posts ? (
<div>
{this.state.posts.map((post: Status) => {
return <Post key={post.id} post={post} client={this.client} />;
return (
<Post
key={post.id}
post={post}
client={this.client}
/>
);
})}
<br />
{this.state.viewDidLoad && !this.state.viewDidError ? (
{this.state.viewDidLoad &&
!this.state.viewDidError ? (
<div
style={{ textAlign: "center" }}
onClick={() => this.loadMoreTimelinePieces()}
onClick={() =>
this.loadMoreTimelinePieces()
}
>
<Button variant="contained">Load more</Button>
<Button variant="contained">
Load more
</Button>
</div>
) : null}
</div>
@ -458,7 +503,10 @@ class ProfilePage extends Component<any, IProfilePageState> {
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />
@ -472,8 +520,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure you want to block this person? You won't see their
posts on your home feed, local timeline, or public timeline.
Are you sure you want to block this person? You
won't see their posts on your home feed, local
timeline, or public timeline.
</DialogContentText>
</DialogContent>
<DialogActions>

View File

@ -167,8 +167,12 @@ class PublicPage extends Component<any, IPublicPageState> {
<ArrowUpwardIcon />
</Avatar>
}
label={`View ${this.state.backlogPosts.length} new post${
this.state.backlogPosts.length > 1 ? "s" : ""
label={`View ${
this.state.backlogPosts.length
} new post${
this.state.backlogPosts.length > 1
? "s"
: ""
}`}
color="primary"
className={classes.pageTopChip}
@ -182,7 +186,13 @@ class PublicPage extends Component<any, IPublicPageState> {
{this.state.posts ? (
<div>
{this.state.posts.map((post: Status) => {
return <Post key={post.id} post={post} client={this.client} />;
return (
<Post
key={post.id}
post={post}
client={this.client}
/>
);
})}
<br />
{this.state.viewDidLoad && !this.state.viewDidError ? (
@ -204,7 +214,9 @@ class PublicPage extends Component<any, IPublicPageState> {
Something went wrong when loading this timeline.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -212,7 +224,10 @@ class PublicPage extends Component<any, IPublicPageState> {
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />

View File

@ -96,23 +96,31 @@ class RecommendationsPage extends Component<
this.client
.post(`/accounts/${acct.id}/follow`)
.then((resp: any) => {
this.props.enqueueSnackbar("You are now following this account.");
this.props.enqueueSnackbar(
"You are now following this account."
);
this.client.del(`/suggestions/${acct.id}`).then((resp: any) => {
let followSuggestions = this.state.followSuggestions;
if (followSuggestions) {
followSuggestions.forEach((suggestion: Account, index: number) => {
if (followSuggestions && suggestion.id === acct.id) {
followSuggestions.forEach(
(suggestion: Account, index: number) => {
if (
followSuggestions &&
suggestion.id === acct.id
) {
followSuggestions.splice(index, 1);
}
});
}
);
this.setState({ followSuggestions });
}
});
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't follow account: " + err.name,
{ variant: "error" }
);
console.error(err.message);
});
}
@ -123,16 +131,20 @@ class RecommendationsPage extends Component<
.then((resp: any) => {
let requestedFollows = this.state.requestedFollows;
if (requestedFollows) {
requestedFollows.forEach((request: Account, index: number) => {
requestedFollows.forEach(
(request: Account, index: number) => {
if (requestedFollows && request.id === acct.id) {
requestedFollows.splice(index, 1);
}
});
}
);
}
this.setState({ requestedFollows });
let verb: string = type;
verb === "authorize" ? (verb = "authorized") : (verb = "rejected");
verb === "authorize"
? (verb = "authorized")
: (verb = "rejected");
this.props.enqueueSnackbar(`You have ${verb} this request.`);
})
.catch((err: Error) => {
@ -152,25 +164,34 @@ class RecommendationsPage extends Component<
<Paper className={classes.pageListConstraints}>
<List>
{this.state.requestedFollows
? this.state.requestedFollows.map((request: Account) => {
? this.state.requestedFollows.map(
(request: Account) => {
return (
<ListItem key={request.id}>
<ListItemAvatar>
<LinkableAvatar
to={`/profile/${request.id}`}
alt={request.username}
src={request.avatar_static}
src={
request.avatar_static
}
/>
</ListItemAvatar>
<ListItemText
primary={request.display_name || request.acct}
primary={
request.display_name ||
request.acct
}
secondary={request.acct}
/>
<ListItemSecondaryAction>
<Tooltip title="Accept request">
<IconButton
onClick={() =>
this.handleFollowRequest(request, "authorize")
this.handleFollowRequest(
request,
"authorize"
)
}
>
<CheckIcon />
@ -179,21 +200,27 @@ class RecommendationsPage extends Component<
<Tooltip title="Reject request">
<IconButton
onClick={() =>
this.handleFollowRequest(request, "reject")
this.handleFollowRequest(
request,
"reject"
)
}
>
<CloseIcon />
</IconButton>
</Tooltip>
<Tooltip title="View profile">
<LinkableIconButton to={`/profile/${request.id}`}>
<LinkableIconButton
to={`/profile/${request.id}`}
>
<AccountCircleIcon />
</LinkableIconButton>
</Tooltip>
</ListItemSecondaryAction>
</ListItem>
);
})
}
)
: null}
</List>
</Paper>
@ -210,29 +237,41 @@ class RecommendationsPage extends Component<
<Paper className={classes.pageListConstraints}>
<List>
{this.state.followSuggestions
? this.state.followSuggestions.map((suggestion: Account) => {
? this.state.followSuggestions.map(
(suggestion: Account) => {
return (
<ListItem key={suggestion.id}>
<ListItemAvatar>
<LinkableAvatar
to={`/profile/${suggestion.id}`}
alt={suggestion.username}
src={suggestion.avatar_static}
src={
suggestion.avatar_static
}
/>
</ListItemAvatar>
<ListItemText
primary={suggestion.display_name || suggestion.acct}
primary={
suggestion.display_name ||
suggestion.acct
}
secondary={suggestion.acct}
/>
<ListItemSecondaryAction>
<Tooltip title="View profile">
<LinkableIconButton to={`/profile/${suggestion.id}`}>
<LinkableIconButton
to={`/profile/${suggestion.id}`}
>
<AssignmentIndIcon />
</LinkableIconButton>
</Tooltip>
<Tooltip title="Follow">
<IconButton
onClick={() => this.followMember(suggestion)}
onClick={() =>
this.followMember(
suggestion
)
}
>
<PersonAddIcon />
</IconButton>
@ -240,7 +279,8 @@ class RecommendationsPage extends Component<
</ListItemSecondaryAction>
</ListItem>
);
})
}
)
: null}
</List>
</Paper>
@ -259,7 +299,11 @@ class RecommendationsPage extends Component<
this.state.requestedFollows.length > 0 ? (
this.showFollowRequests()
) : (
<div className={classes.pageLayoutEmptyTextConstraints}>
<div
className={
classes.pageLayoutEmptyTextConstraints
}
>
<Typography variant="h6">
You don't have any follow requests.
</Typography>
@ -272,13 +316,17 @@ class RecommendationsPage extends Component<
this.state.followSuggestions.length > 0 ? (
this.showFollowSuggestions()
) : (
<div className={classes.pageLayoutEmptyTextConstraints}>
<div
className={
classes.pageLayoutEmptyTextConstraints
}
>
<Typography variant="h5">
We don't have any suggestions for you.
</Typography>
<Typography paragraph>
Why not interact with the fediverse a bit by creating a new
post?
Why not interact with the fediverse a bit by
creating a new post?
</Typography>
</div>
)}
@ -291,7 +339,9 @@ class RecommendationsPage extends Component<
Something went wrong when loading this timeline.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -299,7 +349,10 @@ class RecommendationsPage extends Component<
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />

View File

@ -179,12 +179,15 @@ class SearchPage extends Component<any, ISearchPageState> {
client
.post(`/accounts/${acct.id}/follow`)
.then((resp: any) => {
this.props.enqueueSnackbar("You are now following this account.");
this.props.enqueueSnackbar(
"You are now following this account."
);
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
variant: "error"
});
this.props.enqueueSnackbar(
"Couldn't follow account: " + err.name,
{ variant: "error" }
);
console.error(err.message);
});
}
@ -195,10 +198,12 @@ class SearchPage extends Component<any, ISearchPageState> {
<div>
<ListSubheader>Accounts</ListSubheader>
{this.state.results && this.state.results.accounts.length > 0 ? (
{this.state.results &&
this.state.results.accounts.length > 0 ? (
<Paper className={classes.pageListConstraints}>
<List>
{this.state.results.accounts.map((acct: Account) => {
{this.state.results.accounts.map(
(acct: Account) => {
return (
<ListItem key={acct.id}>
<ListItemAvatar>
@ -209,18 +214,27 @@ class SearchPage extends Component<any, ISearchPageState> {
/>
</ListItemAvatar>
<ListItemText
primary={acct.display_name || acct.acct}
primary={
acct.display_name ||
acct.acct
}
secondary={acct.acct}
/>
<ListItemSecondaryAction>
<Tooltip title="View profile">
<LinkableIconButton to={`/profile/${acct.id}`}>
<LinkableIconButton
to={`/profile/${acct.id}`}
>
<AssignmentIndIcon />
</LinkableIconButton>
</Tooltip>
<Tooltip title="Follow">
<IconButton
onClick={() => this.followMemberFromQuery(acct)}
onClick={() =>
this.followMemberFromQuery(
acct
)
}
>
<PersonAddIcon />
</IconButton>
@ -228,7 +242,8 @@ class SearchPage extends Component<any, ISearchPageState> {
</ListItemSecondaryAction>
</ListItem>
);
})}
}
)}
</List>
</Paper>
) : (
@ -253,7 +268,13 @@ class SearchPage extends Component<any, ISearchPageState> {
{this.state.results ? (
this.state.results.statuses.length > 0 ? (
this.state.results.statuses.map((post: Status) => {
return <Post key={post.id} post={post} client={this.client} />;
return (
<Post
key={post.id}
post={post}
client={this.client}
/>
);
})
) : (
<Typography
@ -276,7 +297,13 @@ class SearchPage extends Component<any, ISearchPageState> {
{this.state.tagResults ? (
this.state.tagResults.length > 0 ? (
this.state.tagResults.map((post: Status) => {
return <Post key={post.id} post={post} client={this.client} />;
return (
<Post
key={post.id}
post={post}
client={this.client}
/>
);
})
) : (
<Typography
@ -310,7 +337,9 @@ class SearchPage extends Component<any, ISearchPageState> {
Something went wrong when loading this timeline.
</Typography>
<Typography>
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
{this.state.viewDidErrorCode
? this.state.viewDidErrorCode
: ""}
</Typography>
</Paper>
) : (
@ -318,7 +347,10 @@ class SearchPage extends Component<any, ISearchPageState> {
)}
{this.state.viewIsLoading ? (
<div style={{ textAlign: "center" }}>
<CircularProgress className={classes.progress} color="primary" />
<CircularProgress
className={classes.progress}
color="primary"
/>
</div>
) : (
<span />

View File

@ -46,7 +46,6 @@ import {
} from "../utilities/themes";
import { Visibility } from "../types/Visibility";
import { LinkableButton } from "../interfaces/overrides";
import { Config } from "../types/Config";
import OpenInNewIcon from "@material-ui/icons/OpenInNew";
import DevicesIcon from "@material-ui/icons/Devices";
@ -59,7 +58,7 @@ import NotificationsIcon from "@material-ui/icons/Notifications";
import BellAlertIcon from "mdi-material-ui/BellAlert";
import RefreshIcon from "@material-ui/icons/Refresh";
import UndoIcon from "@material-ui/icons/Undo";
import DomainDisablbedIcon from "@material-ui/icons/DomainDisabled";
import { Config } from "../types/Config";
interface ISettingsState {
darkModeEnabled: boolean;
@ -500,20 +499,6 @@ class SettingsPage extends Component<any, ISettingsState> {
<LinkableButton to="/you">Edit</LinkableButton>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemAvatar>
<DomainDisablbedIcon color="action" />
</ListItemAvatar>
<ListItemText
primary="Manage blocked servers"
secondary="View and manage servers that you've blocked"
/>
<ListItemSecondaryAction>
<LinkableButton to="/blocked">
Manage
</LinkableButton>
</ListItemSecondaryAction>
</ListItem>
<ListItem>
<ListItemAvatar>
<MastodonIcon color="action" />

View File

@ -17,11 +17,7 @@ import {
import { styles } from "./WelcomePage.styles";
import Mastodon from "megalodon";
import { SaveClientSession } from "../types/SessionData";
import {
createHyperspaceApp,
getRedirectAddress,
inDisallowedDomains
} from "../utilities/login";
import { createHyperspaceApp, getRedirectAddress } from "../utilities/login";
import { parseUrl } from "query-string";
import { getConfig } from "../utilities/settings";
import { isDarwinApp } from "../utilities/desktop";
@ -83,17 +79,9 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
let config: Config = result;
if (result.location === "dynamic") {
console.warn(
"Redirect URI is set to dynamic, which may affect how sign-in works for some users. Careful!"
"Recirect URI is set to dynamic, which may affect how sign-in works for some users. Careful!"
);
}
if (
inDisallowedDomains(result.registration.defaultInstance)
) {
console.warn(
`The default instance field in config.json contains an unsupported domain (${result.registration.defaultInstance}), so it's been reset to mastodon.social.`
);
result.registration.defaultInstance = "mastodon.social";
}
this.setState({
logoUrl: config.branding
? result.branding.logo
@ -322,19 +310,8 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
if (this.state.user.includes("@")) {
if (this.state.federates && this.state.federates === true) {
let baseUrl = this.state.user.split("@")[1];
if (inDisallowedDomains(baseUrl)) {
this.setState({
userInputError: true,
userInputErrorMessage: `Signing in with an account from ${baseUrl} isn't supported.`
});
return true;
} else {
axios
.get(
"https://" +
baseUrl +
"/api/v1/timelines/public"
)
.get("https://" + baseUrl + "/api/v1/timelines/public")
.catch((err: Error) => {
let userInputError = true;
let userInputErrorMessage =
@ -345,7 +322,6 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
});
return true;
});
}
} else if (
this.state.user.includes(
this.state.registerBase
@ -726,8 +702,7 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
{this.state.brandName
? this.state.brandName
: "Hypersapce"}{" "}
v.
{this.state.version}{" "}
v.{this.state.version}{" "}
{this.state.brandName &&
this.state.brandName !== "Hyperspace"
? "(Hyperspace-like)"

View File

@ -71,9 +71,14 @@ class You extends Component<IYouProps, IYouState> {
.then((acct: any) => {
let currentAccount: Account = acct.data;
this.setState({ currentAccount });
localStorage.setItem("account", JSON.stringify(currentAccount));
localStorage.setItem(
"account",
JSON.stringify(currentAccount)
);
this.props.closeSnackbar("persistAvatar");
this.props.enqueueSnackbar("Avatar updated successfully.");
this.props.enqueueSnackbar(
"Avatar updated successfully."
);
})
.catch((err: Error) => {
this.props.closeSnackbar("persistAvatar");
@ -85,7 +90,9 @@ class You extends Component<IYouProps, IYouState> {
}
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't update avatar: " + err.name);
this.props.enqueueSnackbar(
"Couldn't update avatar: " + err.name
);
});
}
@ -107,9 +114,14 @@ class You extends Component<IYouProps, IYouState> {
.then((acct: any) => {
let currentAccount: Account = acct.data;
this.setState({ currentAccount });
localStorage.setItem("account", JSON.stringify(currentAccount));
localStorage.setItem(
"account",
JSON.stringify(currentAccount)
);
this.props.closeSnackbar("persistHeader");
this.props.enqueueSnackbar("Header updated successfully.");
this.props.enqueueSnackbar(
"Header updated successfully."
);
})
.catch((err: Error) => {
this.props.closeSnackbar("persistHeader");
@ -121,7 +133,9 @@ class You extends Component<IYouProps, IYouState> {
}
})
.catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't update header: " + err.name);
this.props.enqueueSnackbar(
"Couldn't update header: " + err.name
);
});
}
@ -157,7 +171,7 @@ class You extends Component<IYouProps, IYouState> {
});
}
updateDisplayname(name: string) {
updateDisplayName(name: string) {
this.setState({ newDisplayName: name });
}
changeBio() {
@ -198,15 +212,27 @@ class You extends Component<IYouProps, IYouState> {
backgroundImage: `url("${this.state.currentAccount.header_static}")`
}}
/>
<div className={classes.pageHeroContent}>
<div className={classes.profileContent}>
<br />
<Avatar
className={classes.pageProfileAvatar}
className={classes.profileAvatar}
src={this.state.currentAccount.avatar_static}
/>
<Typography variant="h4" color="inherit" component="h1">
<div
className={classes.profileUserBox}
style={{ paddingTop: 8, paddingBottom: 8 }}
>
<Typography
variant="h4"
color="inherit"
component="h1"
>
Edit your profile
</Typography>
<br />
<Typography color="inherit">
Change information such as your display name,
bio, and images used here.
</Typography>
<div>
<Button
className={classes.pageProfileFollowButton}
@ -223,7 +249,7 @@ class You extends Component<IYouProps, IYouState> {
Change Header
</Button>
</div>
<br />
</div>
</div>
</div>
<div className={classes.pageContentLayoutConstraints}>
@ -234,14 +260,16 @@ class You extends Component<IYouProps, IYouState> {
<br />
<TextField
className={classes.TextField}
defaultValue={this.state.currentAccount.display_name}
defaultValue={
this.state.currentAccount.display_name
}
rowsMax="1"
variant="outlined"
fullWidth
onChange={(event: any) =>
this.updateDisplayname(event.target.value)
this.updateDisplayName(event.target.value)
}
></TextField>
/>
<div style={{ textAlign: "right" }}>
<Button
className={classes.pageProfileFollowButton}
@ -262,7 +290,9 @@ class You extends Component<IYouProps, IYouState> {
className={classes.TextField}
defaultValue={
this.state.currentAccount.note
? this.removeHTMLContent(this.state.currentAccount.note)
? this.removeHTMLContent(
this.state.currentAccount.note
)
: "Tell a little bit about yourself"
}
multiline
@ -270,8 +300,10 @@ class You extends Component<IYouProps, IYouState> {
rows="2"
rowsMax="5"
fullWidth
onChange={(event: any) => this.updateBio(event.target.value)}
></TextField>
onChange={(event: any) =>
this.updateBio(event.target.value)
}
/>
<div style={{ textAlign: "right" }}>
<Button
className={classes.pageProfileFollowButton}

View File

@ -1,7 +1,10 @@
import Mastodon from "megalodon";
export function userLoggedIn(): boolean {
if (localStorage.getItem("baseurl") && localStorage.getItem("access_token")) {
if (
localStorage.getItem("baseurl") &&
localStorage.getItem("access_token")
) {
return true;
} else {
return false;

View File

@ -55,13 +55,3 @@ export function getRedirectAddress(
return type;
}
}
/**
* Determine whether a base URL is in the 'disallowed' domains section.
* @param domain The URL to test
* @returns Boolean dictating the URL's presence in disallowed domains
*/
export function inDisallowedDomains(domain: string): boolean {
let disallowed = ["gab.com"];
return disallowed.includes(domain);
}

View File

@ -135,7 +135,8 @@ export async function getConfig(): Promise<Config | undefined> {
return config;
} catch (err) {
console.error(
"Couldn't configure Hyperspace with the config file. Reason: " + err.name
"Couldn't configure Hyperspace with the config file. Reason: " +
err.name
);
}
}