Merge pull request #85 from hyperspacedev/small-refinements-b
Small refinements and touch-ups
This commit is contained in:
commit
1a4d4120aa
|
@ -1297,6 +1297,12 @@
|
||||||
"@types/react": "*"
|
"@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": {
|
"@types/history": {
|
||||||
"version": "4.7.2",
|
"version": "4.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.2.tgz",
|
||||||
|
@ -1491,12 +1497,13 @@
|
||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/ws": {
|
"@types/websocket": {
|
||||||
"version": "6.0.3",
|
"version": "0.0.40",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-0.0.40.tgz",
|
||||||
"integrity": "sha512-yBTM0P05Tx9iXGq00BbJPo37ox68R5vaGTXivs6RGh/BQ6QP5zqZDGWdAO6JbRE/iR1l80xeGAwCQS2nMV9S/w==",
|
"integrity": "sha512-ldteZwWIgl9cOy7FyvYn+39Ah4+PfpVE72eYKw75iy2L0zTbhbcwvzeJ5IOu6DQP93bjfXq0NGHY6FYtmYoqFQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@types/events": "*",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -12191,19 +12198,19 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"megalodon": {
|
"megalodon": {
|
||||||
"version": "1.0.3",
|
"version": "0.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/megalodon/-/megalodon-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/megalodon/-/megalodon-0.6.4.tgz",
|
||||||
"integrity": "sha512-RcJT3HRWCXQcE5ZQUpLEjJ+HgWvwoTpXr4XLUf0tWrtmxrDnIW43pOASDb3G7MOBKYonzM1pMfAmR2Yfh3Qw/g==",
|
"integrity": "sha512-WGYhcSxGYlBwZSm5VebxLqnbpPemum9/6lJUi1HBsVzF5jXc9fdumhXH0vqGhWdovdqRT86iXBDJl5SwUrbr2A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/oauth": "^0.9.0",
|
"@types/oauth": "^0.9.0",
|
||||||
"@types/request": "^2.47.0",
|
"@types/request": "^2.47.0",
|
||||||
"@types/ws": "^6.0.1",
|
"@types/websocket": "0.0.40",
|
||||||
"axios": "^0.18.1",
|
"axios": "^0.18.0",
|
||||||
"oauth": "^0.9.15",
|
"oauth": "^0.9.15",
|
||||||
"request": "^2.87.0",
|
"request": "^2.87.0",
|
||||||
"typescript": "^3.4.5",
|
"typescript": "^2.9.1",
|
||||||
"ws": "^7.0.1"
|
"websocket": "^1.0.28"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": {
|
"axios": {
|
||||||
|
@ -12247,19 +12254,10 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.6.3",
|
"version": "2.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
|
||||||
"integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
|
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
|
||||||
"dev": true
|
"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=",
|
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||||
"dev": true
|
"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": {
|
"typescript": {
|
||||||
"version": "3.4.1",
|
"version": "3.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.1.tgz",
|
"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": {
|
"websocket-driver": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
|
||||||
|
@ -21368,6 +21410,12 @@
|
||||||
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
|
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
|
||||||
"dev": true
|
"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": {
|
"yallist": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||||
|
|
|
@ -25,10 +25,10 @@
|
||||||
"file-dialog": "^0.0.7",
|
"file-dialog": "^0.0.7",
|
||||||
"material-ui-pickers": "^2.2.4",
|
"material-ui-pickers": "^2.2.4",
|
||||||
"mdi-material-ui": "^5.13.0",
|
"mdi-material-ui": "^5.13.0",
|
||||||
"megalodon": "^1.0.3",
|
"megalodon": "^0.6.4",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"notistack": "^0.5.1",
|
"notistack": "^0.5.1",
|
||||||
"prettier": "^1.18.2",
|
"prettier": "1.18.2",
|
||||||
"query-string": "^6.8.2",
|
"query-string": "^6.8.2",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
|
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 3.3 MiB |
|
@ -20,7 +20,6 @@ import MessagesPage from "./pages/Messages";
|
||||||
import RecommendationsPage from "./pages/Recommendations";
|
import RecommendationsPage from "./pages/Recommendations";
|
||||||
import Missingno from "./pages/Missingno";
|
import Missingno from "./pages/Missingno";
|
||||||
import You from "./pages/You";
|
import You from "./pages/You";
|
||||||
import Blocked from "./pages/Blocked";
|
|
||||||
import { withSnackbar } from "notistack";
|
import { withSnackbar } from "notistack";
|
||||||
import { PrivateRoute } from "./interfaces/overrides";
|
import { PrivateRoute } from "./interfaces/overrides";
|
||||||
import { userLoggedIn } from "./utilities/accounts";
|
import { userLoggedIn } from "./utilities/accounts";
|
||||||
|
@ -57,8 +56,6 @@ class App extends Component<any, any> {
|
||||||
removeBodyBackground() {
|
removeBodyBackground() {
|
||||||
if (isDarwinApp()) {
|
if (isDarwinApp()) {
|
||||||
document.body.style.backgroundColor = "transparent";
|
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}
|
component={Conversation}
|
||||||
/>
|
/>
|
||||||
<PrivateRoute path="/search" component={SearchPage} />
|
<PrivateRoute path="/search" component={SearchPage} />
|
||||||
<PrivateRoute path="/blocked" component={Blocked} />
|
|
||||||
<PrivateRoute path="/settings" component={Settings} />
|
<PrivateRoute path="/settings" component={Settings} />
|
||||||
|
|
||||||
<PrivateRoute path="/you" component={You} />
|
<PrivateRoute path="/you" component={You} />
|
||||||
<PrivateRoute path="/about" component={AboutPage} />
|
<PrivateRoute path="/about" component={AboutPage} />
|
||||||
<PrivateRoute path="/compose" component={Composer} />
|
<PrivateRoute path="/compose" component={Composer} />
|
||||||
|
|
|
@ -46,7 +46,7 @@ export const styles = (theme: Theme) =>
|
||||||
borderBottomColor: darken(theme.palette.primary.dark, 0.2),
|
borderBottomColor: darken(theme.palette.primary.dark, 0.2),
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomStyle: isDarwinApp() ? "solid" : "none",
|
borderBottomStyle: isDarwinApp() ? "solid" : "none",
|
||||||
boxShadow: isDarwinApp() ? "none" : "inherit"
|
boxShadow: isDarwinApp() ? "none" : theme.shadows["4"]
|
||||||
},
|
},
|
||||||
appBarMenuButton: {
|
appBarMenuButton: {
|
||||||
marginLeft: -12,
|
marginLeft: -12,
|
||||||
|
|
|
@ -103,7 +103,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
this.setState({ currentUser: data });
|
this.setState({ currentUser: data });
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.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);
|
console.error(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -113,7 +115,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
let config: Config = result;
|
let config: Config = result;
|
||||||
this.setState({
|
this.setState({
|
||||||
enableFederation: config.federation.enablePublicTimeline,
|
enableFederation: config.federation.enablePublicTimeline,
|
||||||
brandName: config.branding ? config.branding.name : "Hyperspace",
|
brandName: config.branding
|
||||||
|
? config.branding.name
|
||||||
|
: "Hyperspace",
|
||||||
developerMode: config.developer
|
developerMode: config.developer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -142,40 +146,53 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
switch (notif.type) {
|
switch (notif.type) {
|
||||||
case "favourite":
|
case "favourite":
|
||||||
primaryMessage =
|
primaryMessage =
|
||||||
(notif.account.display_name || "@" + notif.account.username) +
|
(notif.account.display_name ||
|
||||||
|
"@" + notif.account.username) +
|
||||||
" favorited your post.";
|
" favorited your post.";
|
||||||
if (notif.status) {
|
if (notif.status) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.innerHTML = notif.status.content;
|
div.innerHTML = notif.status.content;
|
||||||
secondaryMessage =
|
secondaryMessage =
|
||||||
(div.textContent || div.innerText || "").slice(0, 100) + "...";
|
(div.textContent || div.innerText || "").slice(
|
||||||
|
0,
|
||||||
|
100
|
||||||
|
) + "...";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "follow":
|
case "follow":
|
||||||
primaryMessage =
|
primaryMessage =
|
||||||
(notif.account.display_name || "@" + notif.account.username) +
|
(notif.account.display_name ||
|
||||||
|
"@" + notif.account.username) +
|
||||||
" is now following you.";
|
" is now following you.";
|
||||||
break;
|
break;
|
||||||
case "mention":
|
case "mention":
|
||||||
primaryMessage =
|
primaryMessage =
|
||||||
(notif.account.display_name || "@" + notif.account.username) +
|
(notif.account.display_name ||
|
||||||
|
"@" + notif.account.username) +
|
||||||
" mentioned you in a post.";
|
" mentioned you in a post.";
|
||||||
if (notif.status) {
|
if (notif.status) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.innerHTML = notif.status.content;
|
div.innerHTML = notif.status.content;
|
||||||
secondaryMessage =
|
secondaryMessage =
|
||||||
(div.textContent || div.innerText || "").slice(0, 100) + "...";
|
(div.textContent || div.innerText || "").slice(
|
||||||
|
0,
|
||||||
|
100
|
||||||
|
) + "...";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "reblog":
|
case "reblog":
|
||||||
primaryMessage =
|
primaryMessage =
|
||||||
(notif.account.display_name || "@" + notif.account.username) +
|
(notif.account.display_name ||
|
||||||
|
"@" + notif.account.username) +
|
||||||
" reblogged your post.";
|
" reblogged your post.";
|
||||||
if (notif.status) {
|
if (notif.status) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.innerHTML = notif.status.content;
|
div.innerHTML = notif.status.content;
|
||||||
secondaryMessage =
|
secondaryMessage =
|
||||||
(div.textContent || div.innerText || "").slice(0, 100) + "...";
|
(div.textContent || div.innerText || "").slice(
|
||||||
|
0,
|
||||||
|
100
|
||||||
|
) + "...";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -229,15 +246,14 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
return (
|
return (
|
||||||
<div className={classes.titleBarRoot}>
|
<div className={classes.titleBarRoot}>
|
||||||
<Typography className={classes.titleBarText}>
|
<Typography className={classes.titleBarText}>
|
||||||
{this.state.brandName ? this.state.brandName : "Hyperspace"}{" "}
|
{this.state.brandName
|
||||||
{this.state.developerMode ? "(beta)" : null}
|
? this.state.brandName
|
||||||
|
: "Hyperspace"}{" "}
|
||||||
|
{this.state.developerMode ? "(Beta)" : null}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (process.env.NODE_ENV === "development") {
|
||||||
this.state.developerMode ||
|
|
||||||
process.env.NODE_ENV === "development"
|
|
||||||
) {
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.titleBarRoot}>
|
<div className={classes.titleBarRoot}>
|
||||||
<Typography className={classes.titleBarText}>
|
<Typography className={classes.titleBarText}>
|
||||||
|
@ -258,7 +274,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
button
|
button
|
||||||
key="profile-mobile"
|
key="profile-mobile"
|
||||||
to={`/profile/${
|
to={`/profile/${
|
||||||
this.state.currentUser ? this.state.currentUser.id : "1"
|
this.state.currentUser
|
||||||
|
? this.state.currentUser.id
|
||||||
|
: "1"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
|
@ -266,7 +284,8 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
alt="You"
|
alt="You"
|
||||||
src={
|
src={
|
||||||
this.state.currentUser
|
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>
|
<ListItemIcon>
|
||||||
<PublicIcon />
|
<PublicIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Public" secondary="Disabled by admin" />
|
<ListItemText
|
||||||
|
primary="Public"
|
||||||
|
secondary="Disabled by admin"
|
||||||
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
)}
|
)}
|
||||||
<Divider />
|
<Divider />
|
||||||
|
@ -351,7 +373,11 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Notifications" />
|
<ListItemText primary="Notifications" />
|
||||||
</LinkableListItem>
|
</LinkableListItem>
|
||||||
<LinkableListItem button key="messages-mobile" to="/messages">
|
<LinkableListItem
|
||||||
|
button
|
||||||
|
key="messages-mobile"
|
||||||
|
to="/messages"
|
||||||
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<MailIcon />
|
<MailIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
@ -360,7 +386,11 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
<Divider />
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
<ListSubheader>More</ListSubheader>
|
<ListSubheader>More</ListSubheader>
|
||||||
<LinkableListItem button key="recommended" to="/recommended">
|
<LinkableListItem
|
||||||
|
button
|
||||||
|
key="recommended"
|
||||||
|
to="/recommended"
|
||||||
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<GroupIcon />
|
<GroupIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
@ -405,7 +435,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
color="inherit"
|
color="inherit"
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
{this.state.brandName ? this.state.brandName : "Hyperspace"}
|
{this.state.brandName
|
||||||
|
? this.state.brandName
|
||||||
|
: "Hyperspace"}
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={classes.appBarFlexGrow} />
|
<div className={classes.appBarFlexGrow} />
|
||||||
<div className={classes.appBarSearch}>
|
<div className={classes.appBarSearch}>
|
||||||
|
@ -420,7 +452,9 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
}}
|
}}
|
||||||
onKeyUp={event => {
|
onKeyUp={event => {
|
||||||
if (event.keyCode === 13) {
|
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
|
<Badge
|
||||||
badgeContent={
|
badgeContent={
|
||||||
this.state.notificationCount > 0
|
this.state.notificationCount > 0
|
||||||
? this.state.notificationCount
|
? this.state
|
||||||
|
.notificationCount
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
@ -446,18 +481,27 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Direct messages">
|
<Tooltip title="Direct messages">
|
||||||
<LinkableIconButton color="inherit" to="/messages">
|
<LinkableIconButton
|
||||||
|
color="inherit"
|
||||||
|
to="/messages"
|
||||||
|
>
|
||||||
<MailIcon />
|
<MailIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Your account">
|
<Tooltip title="Your account">
|
||||||
<IconButton id="acctMenuBtn" onClick={this.toggleAcctMenu}>
|
<IconButton
|
||||||
|
id="acctMenuBtn"
|
||||||
|
onClick={this.toggleAcctMenu}
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
className={classes.appBarAcctMenuIcon}
|
className={
|
||||||
|
classes.appBarAcctMenuIcon
|
||||||
|
}
|
||||||
alt="You"
|
alt="You"
|
||||||
src={
|
src={
|
||||||
this.state.currentUser
|
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
|
<Menu
|
||||||
id="acct-menu"
|
id="acct-menu"
|
||||||
anchorEl={document.getElementById("acctMenuBtn")}
|
anchorEl={document.getElementById(
|
||||||
|
"acctMenuBtn"
|
||||||
|
)}
|
||||||
open={this.state.acctMenuOpen}
|
open={this.state.acctMenuOpen}
|
||||||
className={classes.acctMenu}
|
className={classes.acctMenu}
|
||||||
>
|
>
|
||||||
<ClickAwayListener onClickAway={this.toggleAcctMenu}>
|
<ClickAwayListener
|
||||||
|
onClickAway={this.toggleAcctMenu}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<LinkableListItem
|
<LinkableListItem
|
||||||
to={`/profile/${
|
to={`/profile/${
|
||||||
this.state.currentUser
|
this.state.currentUser
|
||||||
? this.state.currentUser.id
|
? this.state.currentUser
|
||||||
|
.id
|
||||||
: "1"
|
: "1"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
@ -483,8 +532,11 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
<Avatar
|
<Avatar
|
||||||
alt="You"
|
alt="You"
|
||||||
src={
|
src={
|
||||||
this.state.currentUser
|
this.state
|
||||||
? this.state.currentUser.avatar_static
|
.currentUser
|
||||||
|
? this.state
|
||||||
|
.currentUser
|
||||||
|
.avatar_static
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -492,21 +544,36 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
this.state.currentUser
|
this.state.currentUser
|
||||||
? this.state.currentUser.display_name ||
|
? this.state
|
||||||
this.state.currentUser.acct
|
.currentUser
|
||||||
|
.display_name ||
|
||||||
|
this.state
|
||||||
|
.currentUser
|
||||||
|
.acct
|
||||||
: "Loading..."
|
: "Loading..."
|
||||||
}
|
}
|
||||||
secondary={
|
secondary={
|
||||||
"@" +
|
"@" +
|
||||||
(this.state.currentUser
|
(this.state.currentUser
|
||||||
? this.state.currentUser.acct
|
? this.state
|
||||||
|
.currentUser
|
||||||
|
.acct
|
||||||
: "Loading...")
|
: "Loading...")
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</LinkableListItem>
|
</LinkableListItem>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
<LinkableListItem to={"/you"}>
|
||||||
|
<ListItemText>
|
||||||
|
Edit profile
|
||||||
|
</ListItemText>
|
||||||
|
</LinkableListItem>
|
||||||
{/* <MenuItem>Switch account</MenuItem> */}
|
{/* <MenuItem>Switch account</MenuItem> */}
|
||||||
<MenuItem onClick={() => this.toggleLogOutDialog()}>
|
<MenuItem
|
||||||
|
onClick={() =>
|
||||||
|
this.toggleLogOutDialog()
|
||||||
|
}
|
||||||
|
>
|
||||||
Log out
|
Log out
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</div>
|
</div>
|
||||||
|
@ -549,14 +616,22 @@ export class AppLayout extends Component<any, IAppLayoutState> {
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">
|
<DialogTitle id="alert-dialog-title">
|
||||||
Log out of{" "}
|
Log out of{" "}
|
||||||
{this.state.brandName ? this.state.brandName : "Hyperspace"}
|
{this.state.brandName
|
||||||
|
? this.state.brandName
|
||||||
|
: "Hyperspace"}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
You'll need to remove{" "}
|
You'll need to remove{" "}
|
||||||
{this.state.brandName ? this.state.brandName : "Hyperspace"} from
|
{this.state.brandName
|
||||||
your list of authorized apps and log in again if you want to use{" "}
|
? this.state.brandName
|
||||||
{this.state.brandName ? this.state.brandName : "Hyperspace"}.
|
: "Hyperspace"}{" "}
|
||||||
|
from your list of authorized apps and log in again
|
||||||
|
if you want to use{" "}
|
||||||
|
{this.state.brandName
|
||||||
|
? this.state.brandName
|
||||||
|
: "Hyperspace"}
|
||||||
|
.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|
|
@ -85,7 +85,9 @@ class AttachmentComponent extends Component<
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "unknown":
|
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
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => this.moveForward()}
|
onClick={() => this.moveForward()}
|
||||||
disabled={this.state.currentStep === this.state.totalSteps - 1}
|
disabled={
|
||||||
|
this.state.currentStep ===
|
||||||
|
this.state.totalSteps - 1
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -48,7 +48,9 @@ class ComposeMediaAttachment extends Component<
|
||||||
this.props.enqueueSnackbar("Description updated.");
|
this.props.enqueueSnackbar("Description updated.");
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.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" ? (
|
{attachment.type === "image" || attachment.type === "gifv" ? (
|
||||||
<img
|
<img
|
||||||
src={attachment.url}
|
src={attachment.url}
|
||||||
alt={attachment.description ? attachment.description : ""}
|
alt={
|
||||||
|
attachment.description ? attachment.description : ""
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
) : attachment.type === "video" ? (
|
) : attachment.type === "video" ? (
|
||||||
<video autoPlay={false} src={attachment.url} />
|
<video autoPlay={false} src={attachment.url} />
|
||||||
|
@ -74,13 +78,19 @@ class ComposeMediaAttachment extends Component<
|
||||||
label="Description"
|
label="Description"
|
||||||
margin="dense"
|
margin="dense"
|
||||||
className={classes.attachmentText}
|
className={classes.attachmentText}
|
||||||
onBlur={event => this.updateAttachmentText(event.target.value)}
|
onBlur={event =>
|
||||||
|
this.updateAttachmentText(event.target.value)
|
||||||
|
}
|
||||||
></TextField>
|
></TextField>
|
||||||
}
|
}
|
||||||
actionIcon={
|
actionIcon={
|
||||||
<IconButton
|
<IconButton
|
||||||
color="inherit"
|
color="inherit"
|
||||||
onClick={() => this.props.onDeleteCallback(this.state.attachment)}
|
onClick={() =>
|
||||||
|
this.props.onDeleteCallback(
|
||||||
|
this.state.attachment
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
|
@ -106,7 +106,9 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
this.client
|
this.client
|
||||||
.del("/statuses/" + this.state.post.id)
|
.del("/statuses/" + this.state.post.id)
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
this.props.enqueueSnackbar("Post deleted. Refresh to see changes.");
|
this.props.enqueueSnackbar(
|
||||||
|
"Post deleted. Refresh to see changes."
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar("Couldn't delete post: " + err.name);
|
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}>
|
<div className={classes.mediaContainer}>
|
||||||
<Typography
|
<Typography
|
||||||
paragraph
|
paragraph
|
||||||
dangerouslySetInnerHTML={{ __html: oldContent.innerHTML }}
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: oldContent.innerHTML
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{status.card ? (
|
{status.card ? (
|
||||||
<div className={classes.postCard}>
|
<div className={classes.postCard}>
|
||||||
|
@ -204,16 +208,24 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography gutterBottom variant="h6" component="h2">
|
<Typography
|
||||||
|
gutterBottom
|
||||||
|
variant="h6"
|
||||||
|
component="h2"
|
||||||
|
>
|
||||||
{status.card.title}
|
{status.card.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{status.card.description.slice(0, 500) +
|
{status.card.description.slice(0, 500) +
|
||||||
(status.card.description.length > 500 ? "..." : "") ||
|
(status.card.description.length >
|
||||||
|
500
|
||||||
|
? "..."
|
||||||
|
: "") ||
|
||||||
"No description provided. Click with caution."}
|
"No description provided. Click with caution."}
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
{status.card.image && status.media_attachments.length <= 0 ? (
|
{status.card.image &&
|
||||||
|
status.media_attachments.length <= 0 ? (
|
||||||
<CardMedia
|
<CardMedia
|
||||||
className={classes.postMedia}
|
className={classes.postMedia}
|
||||||
image={status.card.image}
|
image={status.card.image}
|
||||||
|
@ -243,22 +255,27 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
status.poll.voted || status.poll.expired ? (
|
status.poll.voted || status.poll.expired ? (
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="caption">
|
<Typography variant="caption">
|
||||||
You can't vote on this poll. Below are the results of the
|
You can't vote on this poll. Below are the
|
||||||
poll.
|
results of the poll.
|
||||||
</Typography>
|
</Typography>
|
||||||
<RadioGroup value={this.findBiggestVote()}>
|
<RadioGroup value={this.findBiggestVote()}>
|
||||||
{status.poll.options.map((pollOption: PollOption) => {
|
{status.poll.options.map(
|
||||||
|
(pollOption: PollOption) => {
|
||||||
let x = (
|
let x = (
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
disabled
|
disabled
|
||||||
value={pollOption.title}
|
value={pollOption.title}
|
||||||
control={<Radio />}
|
control={<Radio />}
|
||||||
label={`${pollOption.title} (${pollOption.votes_count} votes)`}
|
label={`${pollOption.title} (${pollOption.votes_count} votes)`}
|
||||||
key={pollOption.title + pollOption.votes_count}
|
key={
|
||||||
|
pollOption.title +
|
||||||
|
pollOption.votes_count
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
return x;
|
return x;
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
{status.poll && status.poll.expired ? (
|
{status.poll && status.poll.expired ? (
|
||||||
<Typography variant="caption">
|
<Typography variant="caption">
|
||||||
|
@ -268,7 +285,9 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
<Typography variant="caption">
|
<Typography variant="caption">
|
||||||
This poll will expire on{" "}
|
This poll will expire on{" "}
|
||||||
{moment(
|
{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")}
|
).format("MMMM Do YYYY, [at] h:mm A")}
|
||||||
.
|
.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -281,17 +300,22 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
this.captureVote(option)
|
this.captureVote(option)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{status.poll.options.map((pollOption: PollOption) => {
|
{status.poll.options.map(
|
||||||
|
(pollOption: PollOption) => {
|
||||||
let x = (
|
let x = (
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
value={pollOption.title}
|
value={pollOption.title}
|
||||||
control={<Radio />}
|
control={<Radio />}
|
||||||
label={pollOption.title}
|
label={pollOption.title}
|
||||||
key={pollOption.title + pollOption.votes_count}
|
key={
|
||||||
|
pollOption.title +
|
||||||
|
pollOption.votes_count
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
return x;
|
return x;
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -338,11 +362,17 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
}
|
}
|
||||||
color="inherit"
|
color="inherit"
|
||||||
>
|
>
|
||||||
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />} color="inherit">
|
<ExpansionPanelSummary
|
||||||
|
expandIcon={<ExpandMoreIcon />}
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
{icon}
|
{icon}
|
||||||
<Typography>{warningText}</Typography>
|
<Typography>{warningText}</Typography>
|
||||||
</ExpansionPanelSummary>
|
</ExpansionPanelSummary>
|
||||||
<ExpansionPanelDetails className={classes.postContent} color="inherit">
|
<ExpansionPanelDetails
|
||||||
|
className={classes.postContent}
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
{this.materializeContent(content)}
|
{this.materializeContent(content)}
|
||||||
</ExpansionPanelDetails>
|
</ExpansionPanelDetails>
|
||||||
</ExpansionPanel>
|
</ExpansionPanel>
|
||||||
|
@ -364,18 +394,21 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
const { classes } = this.props;
|
const { classes } = this.props;
|
||||||
if (post.reblog) {
|
if (post.reblog) {
|
||||||
let author = post.reblog.account;
|
let author = post.reblog.account;
|
||||||
let origString = `<span>${author.display_name || author.username} (@${
|
let origString = `<span>${author.display_name ||
|
||||||
author.acct
|
author.username} (@${author.acct}) 🔄 ${post.account
|
||||||
}) 🔄 ${post.account.display_name || post.account.username}</span>`;
|
.display_name || post.account.username}</span>`;
|
||||||
let emojis = author.emojis;
|
let emojis = author.emojis;
|
||||||
emojis.concat(post.account.emojis);
|
emojis.concat(post.account.emojis);
|
||||||
return emojifyString(origString, emojis, classes.postAuthorEmoji);
|
return emojifyString(origString, emojis, classes.postAuthorEmoji);
|
||||||
} else {
|
} else {
|
||||||
let author = post.account;
|
let author = post.account;
|
||||||
let origString = `<span>${author.display_name || author.username} (@${
|
let origString = `<span>${author.display_name ||
|
||||||
author.acct
|
author.username} (@${author.acct})</span>`;
|
||||||
})</span>`;
|
return emojifyString(
|
||||||
return emojifyString(origString, author.emojis, classes.postAuthorEmoji);
|
origString,
|
||||||
|
author.emojis,
|
||||||
|
classes.postAuthorEmoji
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +427,9 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
</Avatar>
|
</Avatar>
|
||||||
}
|
}
|
||||||
label={person.username}
|
label={person.username}
|
||||||
key={this.state.post.id + "_mention_" + person.id}
|
key={
|
||||||
|
this.state.post.id + "_mention_" + person.id
|
||||||
|
}
|
||||||
to={`/profile/${person.id}`}
|
to={`/profile/${person.id}`}
|
||||||
className={classes.postMention}
|
className={classes.postMention}
|
||||||
clickable
|
clickable
|
||||||
|
@ -481,9 +516,12 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
this.setState({ post });
|
this.setState({ post });
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
_this.props.enqueueSnackbar(`Couldn't unfavorite post: ${err.name}`, {
|
_this.props.enqueueSnackbar(
|
||||||
|
`Couldn't unfavorite post: ${err.name}`,
|
||||||
|
{
|
||||||
variant: "error"
|
variant: "error"
|
||||||
});
|
}
|
||||||
|
);
|
||||||
console.log(err.message);
|
console.log(err.message);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -494,9 +532,12 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
this.setState({ post });
|
this.setState({ post });
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
_this.props.enqueueSnackbar(`Couldn't favorite post: ${err.name}`, {
|
_this.props.enqueueSnackbar(
|
||||||
|
`Couldn't favorite post: ${err.name}`,
|
||||||
|
{
|
||||||
variant: "error"
|
variant: "error"
|
||||||
});
|
}
|
||||||
|
);
|
||||||
console.log(err.message);
|
console.log(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -511,9 +552,12 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
this.setState({ post });
|
this.setState({ post });
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar(`Couldn't unboost post: ${err.name}`, {
|
this.props.enqueueSnackbar(
|
||||||
|
`Couldn't unboost post: ${err.name}`,
|
||||||
|
{
|
||||||
variant: "error"
|
variant: "error"
|
||||||
});
|
}
|
||||||
|
);
|
||||||
console.log(err.message);
|
console.log(err.message);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -524,9 +568,12 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
this.setState({ post });
|
this.setState({ post });
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar(`Couldn't boost post: ${err.name}`, {
|
this.props.enqueueSnackbar(
|
||||||
|
`Couldn't boost post: ${err.name}`,
|
||||||
|
{
|
||||||
variant: "error"
|
variant: "error"
|
||||||
});
|
}
|
||||||
|
);
|
||||||
console.log(err.message);
|
console.log(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -538,11 +585,13 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
open={this.state.deletePostDialog}
|
open={this.state.deletePostDialog}
|
||||||
onClose={() => this.togglePostDeleteDialog()}
|
onClose={() => this.togglePostDeleteDialog()}
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">Delete this post?</DialogTitle>
|
<DialogTitle id="alert-dialog-title">
|
||||||
|
Delete this post?
|
||||||
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
Are you sure you want to delete this post? This action cannot be
|
Are you sure you want to delete this post? This action
|
||||||
undone.
|
cannot be undone.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
@ -577,7 +626,9 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
avatar={
|
avatar={
|
||||||
<LinkableAvatar
|
<LinkableAvatar
|
||||||
to={`/profile/${
|
to={`/profile/${
|
||||||
post.reblog ? post.reblog.account.id : post.account.id
|
post.reblog
|
||||||
|
? post.reblog.account.id
|
||||||
|
: post.account.id
|
||||||
}`}
|
}`}
|
||||||
src={
|
src={
|
||||||
post.reblog
|
post.reblog
|
||||||
|
@ -626,17 +677,23 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
to={`/compose?reply=${
|
to={`/compose?reply=${
|
||||||
post.reblog ? post.reblog.id : post.id
|
post.reblog ? post.reblog.id : post.id
|
||||||
}&visibility=${post.visibility}&acct=${
|
}&visibility=${post.visibility}&acct=${
|
||||||
post.reblog ? post.reblog.account.acct : post.account.acct
|
post.reblog
|
||||||
|
? post.reblog.account.acct
|
||||||
|
: post.account.acct
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<ReplyIcon />
|
<ReplyIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Typography>
|
<Typography>
|
||||||
{post.reblog ? post.reblog.replies_count : post.replies_count}
|
{post.reblog
|
||||||
|
? post.reblog.replies_count
|
||||||
|
: post.replies_count}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Tooltip title="Favorite">
|
<Tooltip title="Favorite">
|
||||||
<IconButton onClick={() => this.toggleFavorited(post)}>
|
<IconButton
|
||||||
|
onClick={() => this.toggleFavorited(post)}
|
||||||
|
>
|
||||||
<FavoriteIcon
|
<FavoriteIcon
|
||||||
className={
|
className={
|
||||||
post.reblog
|
post.reblog
|
||||||
|
@ -656,7 +713,9 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
: post.favourites_count}
|
: post.favourites_count}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Tooltip title="Boost">
|
<Tooltip title="Boost">
|
||||||
<IconButton onClick={() => this.toggleReblogged(post)}>
|
<IconButton
|
||||||
|
onClick={() => this.toggleReblogged(post)}
|
||||||
|
>
|
||||||
<AutorenewIcon
|
<AutorenewIcon
|
||||||
className={
|
className={
|
||||||
post.reblog
|
post.reblog
|
||||||
|
@ -671,16 +730,26 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Typography>
|
<Typography>
|
||||||
{post.reblog ? post.reblog.reblogs_count : post.reblogs_count}
|
{post.reblog
|
||||||
|
? post.reblog.reblogs_count
|
||||||
|
: post.reblogs_count}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Tooltip className={classes.desktopOnly} title="View thread">
|
<Tooltip
|
||||||
|
className={classes.desktopOnly}
|
||||||
|
title="View thread"
|
||||||
|
>
|
||||||
<LinkableIconButton
|
<LinkableIconButton
|
||||||
to={`/conversation/${post.reblog ? post.reblog.id : post.id}`}
|
to={`/conversation/${
|
||||||
|
post.reblog ? post.reblog.id : post.id
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<ForumIcon />
|
<ForumIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip className={classes.desktopOnly} title="Open in Web">
|
<Tooltip
|
||||||
|
className={classes.desktopOnly}
|
||||||
|
title="Open in Web"
|
||||||
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
href={this.getMastodonUrl(post)}
|
href={this.getMastodonUrl(post)}
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
|
@ -722,22 +791,30 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
/>
|
/>
|
||||||
{post.reblog ? (
|
{post.reblog ? (
|
||||||
<div>
|
<div>
|
||||||
<LinkableMenuItem to={`/profile/${post.reblog.account.id}`}>
|
<LinkableMenuItem
|
||||||
|
to={`/profile/${post.reblog.account.id}`}
|
||||||
|
>
|
||||||
View author profile
|
View author profile
|
||||||
</LinkableMenuItem>
|
</LinkableMenuItem>
|
||||||
<LinkableMenuItem to={`/profile/${post.account.id}`}>
|
<LinkableMenuItem
|
||||||
|
to={`/profile/${post.account.id}`}
|
||||||
|
>
|
||||||
View reblogger profile
|
View reblogger profile
|
||||||
</LinkableMenuItem>
|
</LinkableMenuItem>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<LinkableMenuItem to={`/profile/${post.account.id}`}>
|
<LinkableMenuItem
|
||||||
|
to={`/profile/${post.account.id}`}
|
||||||
|
>
|
||||||
View profile
|
View profile
|
||||||
</LinkableMenuItem>
|
</LinkableMenuItem>
|
||||||
)}
|
)}
|
||||||
<div className={classes.mobileOnly}>
|
<div className={classes.mobileOnly}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<LinkableMenuItem
|
<LinkableMenuItem
|
||||||
to={`/conversation/${post.reblog ? post.reblog.id : post.id}`}
|
to={`/conversation/${
|
||||||
|
post.reblog ? post.reblog.id : post.id
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
View thread
|
View thread
|
||||||
</LinkableMenuItem>
|
</LinkableMenuItem>
|
||||||
|
@ -751,10 +828,15 @@ export class Post extends React.Component<any, IPostState> {
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</div>
|
</div>
|
||||||
{post.account.id ==
|
{post.account.id ==
|
||||||
JSON.parse(localStorage.getItem("account") as string).id ? (
|
JSON.parse(localStorage.getItem("account") as string)
|
||||||
|
.id ? (
|
||||||
<div>
|
<div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<MenuItem onClick={() => this.togglePostDeleteDialog()}>
|
<MenuItem
|
||||||
|
onClick={() =>
|
||||||
|
this.togglePostDeleteDialog()
|
||||||
|
}
|
||||||
|
>
|
||||||
Delete
|
Delete
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -37,7 +37,9 @@ class ThemePreview extends Component<IThemePreviewProps, IThemePreviewState> {
|
||||||
<Paper>
|
<Paper>
|
||||||
<AppBar color="primary" position="static">
|
<AppBar color="primary" position="static">
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<MenuIcon style={{ marginRight: 20, marginLeft: -4 }} />
|
<MenuIcon
|
||||||
|
style={{ marginRight: 20, marginLeft: -4 }}
|
||||||
|
/>
|
||||||
<Typography variant="h6" color="inherit">
|
<Typography variant="h6" color="inherit">
|
||||||
Hyperspace
|
Hyperspace
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -57,17 +59,20 @@ class ThemePreview extends Component<IThemePreviewProps, IThemePreviewState> {
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
<br />
|
||||||
<Typography paragraph>
|
<Typography paragraph>
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
Lorem ipsum dolor sit amet, consectetur
|
||||||
vestibulum congue sem ac ornare. In nec imperdiet neque. In
|
adipiscing elit. Nunc vestibulum congue sem ac
|
||||||
eleifend laoreet efficitur. Vestibulum vel odio mattis,
|
ornare. In nec imperdiet neque. In eleifend
|
||||||
scelerisque nibh a, ornare lectus. Phasellus sollicitudin erat
|
laoreet efficitur. Vestibulum vel odio mattis,
|
||||||
et turpis pellentesque consequat. In maximus luctus purus, eu
|
scelerisque nibh a, ornare lectus. Phasellus
|
||||||
molestie elit euismod eu. Pellentesque quam lectus, sagittis
|
sollicitudin erat et turpis pellentesque
|
||||||
eget accumsan in, consequat ut sapien. Morbi aliquet ligula
|
consequat. In maximus luctus purus, eu molestie
|
||||||
erat, id dapibus nunc laoreet at. Integer sodales lacinia
|
elit euismod eu. Pellentesque quam lectus,
|
||||||
finibus. Aliquam augue nibh, eleifend quis consectetur et,
|
sagittis eget accumsan in, consequat ut sapien.
|
||||||
rhoncus ut odio. Lorem ipsum dolor sit amet, consectetur
|
Morbi aliquet ligula erat, id dapibus nunc
|
||||||
adipiscing elit.
|
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>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ textAlign: "right" }}>
|
<div style={{ textAlign: "right" }}>
|
||||||
|
|
|
@ -110,6 +110,135 @@ class AboutPage extends Component<any, IAboutPageState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.pageLayoutConstraints}>
|
<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>
|
<Paper>
|
||||||
<div
|
<div
|
||||||
className={classes.instanceHeaderPaper}
|
className={classes.instanceHeaderPaper}
|
||||||
|
@ -130,13 +259,10 @@ class AboutPage extends Component<any, IAboutPageState> {
|
||||||
>
|
>
|
||||||
<OpenInNewIcon />
|
<OpenInNewIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography
|
<div className={classes.instanceHeaderText}>
|
||||||
className={classes.instanceHeaderText}
|
<Typography variant="h4" component="p">{this.state.instance ? this.state.instance.uri: "Loading..."}</Typography>
|
||||||
variant="h4"
|
<Typography>Server version {this.state.instance? this.state.instance.version: "x.x.x"}</Typography>
|
||||||
component="p"
|
</div>
|
||||||
>
|
|
||||||
{this.state.instance ? this.state.instance.uri : "Loading..."}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
</div>
|
||||||
<List className={classes.pageListConstraints}>
|
<List className={classes.pageListConstraints}>
|
||||||
{localStorage["isPleroma"] == "false" && (
|
{localStorage["isPleroma"] == "false" && (
|
||||||
|
@ -238,168 +364,9 @@ class AboutPage extends Component<any, IAboutPageState> {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<Avatar>
|
|
||||||
<MastodonIcon />
|
|
||||||
</Avatar>
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText
|
|
||||||
primary="Mastodon version"
|
|
||||||
secondary={
|
|
||||||
this.state.instance ? this.state.instance.version : "x.x.x"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</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 />
|
<br />
|
||||||
<ListSubheader>Federation status</ListSubheader>
|
<ListSubheader>Federation status</ListSubheader>
|
||||||
<Paper>
|
<Paper>
|
||||||
|
|
|
@ -180,9 +180,10 @@ class Composer extends Component<any, IComposerState> {
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.closeSnackbar("media-upload");
|
this.props.closeSnackbar("media-upload");
|
||||||
this.props.enqueueSnackbar("Couldn't upload media: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't upload media: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
|
@ -249,7 +250,8 @@ class Composer extends Component<any, IComposerState> {
|
||||||
let expiration = new Date();
|
let expiration = new Date();
|
||||||
let current = new Date();
|
let current = new Date();
|
||||||
expiration.setMinutes(expiration.getMinutes() + 30);
|
expiration.setMinutes(expiration.getMinutes() + 30);
|
||||||
let expiryDifference = expiration.getTime() - current.getTime() / 1000;
|
let expiryDifference =
|
||||||
|
expiration.getTime() - current.getTime() / 1000;
|
||||||
let temporaryPoll: PollWizard = {
|
let temporaryPoll: PollWizard = {
|
||||||
expires_at: expiryDifference.toString(),
|
expires_at: expiryDifference.toString(),
|
||||||
multiple: false,
|
multiple: false,
|
||||||
|
@ -263,7 +265,10 @@ class Composer extends Component<any, IComposerState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
addPollItem() {
|
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 newOption = { title: "New option" };
|
||||||
let options = this.state.poll.options;
|
let options = this.state.poll.options;
|
||||||
let poll = this.state.poll;
|
let poll = this.state.poll;
|
||||||
|
@ -299,7 +304,10 @@ class Composer extends Component<any, IComposerState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
removePollItem(item: string) {
|
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 options = this.state.poll.options;
|
||||||
let poll = this.state.poll;
|
let poll = this.state.poll;
|
||||||
options.forEach((option: PollWizardOption) => {
|
options.forEach((option: PollWizardOption) => {
|
||||||
|
@ -427,16 +435,18 @@ class Composer extends Component<any, IComposerState> {
|
||||||
label="Content warning"
|
label="Content warning"
|
||||||
margin="dense"
|
margin="dense"
|
||||||
onChange={event =>
|
onChange={event =>
|
||||||
this.updateWarningFromField(event.target.value)
|
this.updateWarningFromField(
|
||||||
|
event.target.value
|
||||||
|
)
|
||||||
}
|
}
|
||||||
></TextField>
|
></TextField>
|
||||||
</Fade>
|
</Fade>
|
||||||
) : null}
|
) : null}
|
||||||
{this.state.visibility === "direct" ? (
|
{this.state.visibility === "direct" ? (
|
||||||
<Typography variant="caption">
|
<Typography variant="caption">
|
||||||
<WarningIcon className={classes.warningCaption} /> Don't forget to
|
<WarningIcon className={classes.warningCaption} />{" "}
|
||||||
add the usernames of the accounts you want to message in your
|
Don't forget to add the usernames of the accounts
|
||||||
post.
|
you want to message in your post.
|
||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
@ -446,7 +456,9 @@ class Composer extends Component<any, IComposerState> {
|
||||||
fullWidth
|
fullWidth
|
||||||
placeholder="What's on your mind?"
|
placeholder="What's on your mind?"
|
||||||
margin="normal"
|
margin="normal"
|
||||||
onChange={event => this.updateTextFromField(event.target.value)}
|
onChange={event =>
|
||||||
|
this.updateTextFromField(event.target.value)
|
||||||
|
}
|
||||||
onKeyDown={event => this.postViaKeyboard(event)}
|
onKeyDown={event => this.postViaKeyboard(event)}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
maxLength: 500
|
maxLength: 500
|
||||||
|
@ -465,11 +477,14 @@ class Composer extends Component<any, IComposerState> {
|
||||||
this.state.remainingChars === 1 ? "" : "s"
|
this.state.remainingChars === 1 ? "" : "s"
|
||||||
} remaining`}
|
} remaining`}
|
||||||
</Typography>
|
</Typography>
|
||||||
{this.state.attachments && this.state.attachments.length > 0 ? (
|
{this.state.attachments &&
|
||||||
|
this.state.attachments.length > 0 ? (
|
||||||
<div className={classes.composeAttachmentArea}>
|
<div className={classes.composeAttachmentArea}>
|
||||||
<GridList
|
<GridList
|
||||||
cellHeight={48}
|
cellHeight={48}
|
||||||
className={classes.composeAttachmentAreaGridList}
|
className={
|
||||||
|
classes.composeAttachmentAreaGridList
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<GridListTile
|
<GridListTile
|
||||||
key="Subheader-composer"
|
key="Subheader-composer"
|
||||||
|
@ -478,21 +493,31 @@ class Composer extends Component<any, IComposerState> {
|
||||||
>
|
>
|
||||||
<ListSubheader>Attachments</ListSubheader>
|
<ListSubheader>Attachments</ListSubheader>
|
||||||
</GridListTile>
|
</GridListTile>
|
||||||
{this.state.attachments.map((attachment: Attachment) => {
|
{this.state.attachments.map(
|
||||||
|
(attachment: Attachment) => {
|
||||||
let c = (
|
let c = (
|
||||||
<ComposeMediaAttachment
|
<ComposeMediaAttachment
|
||||||
client={this.client}
|
client={this.client}
|
||||||
attachment={attachment}
|
attachment={attachment}
|
||||||
onAttachmentUpdate={(attachment: Attachment) =>
|
onAttachmentUpdate={(
|
||||||
this.fetchAttachmentAfterUpdate(attachment)
|
attachment: Attachment
|
||||||
|
) =>
|
||||||
|
this.fetchAttachmentAfterUpdate(
|
||||||
|
attachment
|
||||||
|
)
|
||||||
}
|
}
|
||||||
onDeleteCallback={(attachment: Attachment) =>
|
onDeleteCallback={(
|
||||||
this.deleteMediaAttachment(attachment)
|
attachment: Attachment
|
||||||
|
) =>
|
||||||
|
this.deleteMediaAttachment(
|
||||||
|
attachment
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
return c;
|
return c;
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</GridList>
|
</GridList>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -500,25 +525,46 @@ class Composer extends Component<any, IComposerState> {
|
||||||
<div style={{ marginTop: 4 }}>
|
<div style={{ marginTop: 4 }}>
|
||||||
{this.state.poll
|
{this.state.poll
|
||||||
? this.state.poll.options.map(
|
? this.state.poll.options.map(
|
||||||
(option: PollWizardOption, index: number) => {
|
(
|
||||||
|
option: PollWizardOption,
|
||||||
|
index: number
|
||||||
|
) => {
|
||||||
let c = (
|
let c = (
|
||||||
<div
|
<div
|
||||||
style={{ display: "flex" }}
|
style={{ display: "flex" }}
|
||||||
key={"compose_option_" + index.toString()}
|
key={
|
||||||
|
"compose_option_" +
|
||||||
|
index.toString()
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<RadioButtonCheckedIcon
|
<RadioButtonCheckedIcon
|
||||||
className={classes.pollWizardOptionIcon}
|
className={
|
||||||
|
classes.pollWizardOptionIcon
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
onBlur={(event: any) =>
|
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">
|
<Tooltip title="Remove poll option">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => this.removePollItem(option.title)}
|
onClick={() =>
|
||||||
|
this.removePollItem(
|
||||||
|
option.title
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -538,14 +584,18 @@ class Composer extends Component<any, IComposerState> {
|
||||||
: new Date()
|
: new Date()
|
||||||
}
|
}
|
||||||
onChange={(date: any) => {
|
onChange={(date: any) => {
|
||||||
this.setPollExpires(date.toISOString());
|
this.setPollExpires(
|
||||||
|
date.toISOString()
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
label="Poll exipres on"
|
label="Poll exipres on"
|
||||||
disablePast
|
disablePast
|
||||||
/>
|
/>
|
||||||
</MuiPickersUtilsProvider>
|
</MuiPickersUtilsProvider>
|
||||||
<div className={classes.pollWizardFlexGrow} />
|
<div className={classes.pollWizardFlexGrow} />
|
||||||
<Button onClick={() => this.addPollItem()}>Add Option</Button>
|
<Button onClick={() => this.addPollItem()}>
|
||||||
|
Add Option
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -575,16 +625,21 @@ class Composer extends Component<any, IComposerState> {
|
||||||
onClose={() => this.toggleEmojis()}
|
onClose={() => this.toggleEmojis()}
|
||||||
className={classes.composeEmoji}
|
className={classes.composeEmoji}
|
||||||
>
|
>
|
||||||
<EmojiPicker onGetEmoji={(emoji: any) => this.insertEmoji(emoji)} />
|
<EmojiPicker
|
||||||
|
onGetEmoji={(emoji: any) => this.insertEmoji(emoji)}
|
||||||
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Tooltip title="Add/remove a poll">
|
<Tooltip title="Add/remove a poll">
|
||||||
<IconButton
|
<IconButton
|
||||||
disabled={
|
disabled={
|
||||||
this.state.attachments && this.state.attachments.length > 0
|
this.state.attachments &&
|
||||||
|
this.state.attachments.length > 0
|
||||||
}
|
}
|
||||||
id="compose-poll"
|
id="compose-poll"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.state.poll ? this.removePoll() : this.createPoll();
|
this.state.poll
|
||||||
|
? this.removePoll()
|
||||||
|
: this.createPoll();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<HowToVoteIcon />
|
<HowToVoteIcon />
|
||||||
|
@ -611,17 +666,25 @@ class Composer extends Component<any, IComposerState> {
|
||||||
anchorEl={document.getElementById("compose-visibility")}
|
anchorEl={document.getElementById("compose-visibility")}
|
||||||
onClose={() => this.toggleVisibilityMenu()}
|
onClose={() => this.toggleVisibilityMenu()}
|
||||||
>
|
>
|
||||||
<MenuItem onClick={() => this.changeVisibility("direct")}>
|
<MenuItem
|
||||||
|
onClick={() => this.changeVisibility("direct")}
|
||||||
|
>
|
||||||
Direct (direct message)
|
Direct (direct message)
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onClick={() => this.changeVisibility("private")}>
|
<MenuItem
|
||||||
|
onClick={() => this.changeVisibility("private")}
|
||||||
|
>
|
||||||
Private (followers only)
|
Private (followers only)
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onClick={() => this.changeVisibility("unlisted")}>
|
<MenuItem
|
||||||
|
onClick={() => this.changeVisibility("unlisted")}
|
||||||
|
>
|
||||||
Unlisted
|
Unlisted
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{this.state.federated ? (
|
{this.state.federated ? (
|
||||||
<MenuItem onClick={() => this.changeVisibility("public")}>
|
<MenuItem
|
||||||
|
onClick={() => this.changeVisibility("public")}
|
||||||
|
>
|
||||||
Public
|
Public
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -52,9 +52,10 @@ class Conversation extends Component<any, IConversationPageState> {
|
||||||
viewDidError: true,
|
viewDidError: true,
|
||||||
viewDidErrorCode: err.message
|
viewDidErrorCode: err.message
|
||||||
});
|
});
|
||||||
this.props.enqueueSnackbar("Couldn't get conversation: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't get conversation: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
});
|
});
|
||||||
this.client
|
this.client
|
||||||
.get(`/statuses/${this.state.conversationId}/context`)
|
.get(`/statuses/${this.state.conversationId}/context`)
|
||||||
|
@ -81,9 +82,10 @@ class Conversation extends Component<any, IConversationPageState> {
|
||||||
viewDidError: true,
|
viewDidError: true,
|
||||||
viewDidErrorCode: err.message
|
viewDidErrorCode: err.message
|
||||||
});
|
});
|
||||||
this.props.enqueueSnackbar("Couldn't get conversation: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't get conversation: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +119,13 @@ class Conversation extends Component<any, IConversationPageState> {
|
||||||
{this.state.posts ? (
|
{this.state.posts ? (
|
||||||
<div>
|
<div>
|
||||||
{this.state.posts.map((post: Status) => {
|
{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>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@ -130,7 +138,9 @@ class Conversation extends Component<any, IConversationPageState> {
|
||||||
Something went wrong when loading this conversation.
|
Something went wrong when loading this conversation.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -138,7 +148,10 @@ class Conversation extends Component<any, IConversationPageState> {
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|
|
@ -167,8 +167,12 @@ class HomePage extends Component<any, IHomePageState> {
|
||||||
<ArrowUpwardIcon />
|
<ArrowUpwardIcon />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
}
|
}
|
||||||
label={`View ${this.state.backlogPosts.length} new post${
|
label={`View ${
|
||||||
this.state.backlogPosts.length > 1 ? "s" : ""
|
this.state.backlogPosts.length
|
||||||
|
} new post${
|
||||||
|
this.state.backlogPosts.length > 1
|
||||||
|
? "s"
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
color="primary"
|
color="primary"
|
||||||
className={classes.pageTopChip}
|
className={classes.pageTopChip}
|
||||||
|
@ -182,7 +186,13 @@ class HomePage extends Component<any, IHomePageState> {
|
||||||
{this.state.posts ? (
|
{this.state.posts ? (
|
||||||
<div>
|
<div>
|
||||||
{this.state.posts.map((post: Status) => {
|
{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 />
|
<br />
|
||||||
{this.state.viewDidLoad && !this.state.viewDidError ? (
|
{this.state.viewDidLoad && !this.state.viewDidError ? (
|
||||||
|
@ -204,7 +214,9 @@ class HomePage extends Component<any, IHomePageState> {
|
||||||
Something went wrong when loading this timeline.
|
Something went wrong when loading this timeline.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -212,7 +224,10 @@ class HomePage extends Component<any, IHomePageState> {
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|
|
@ -168,8 +168,12 @@ class LocalPage extends Component<any, ILocalPageState> {
|
||||||
<ArrowUpwardIcon />
|
<ArrowUpwardIcon />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
}
|
}
|
||||||
label={`View ${this.state.backlogPosts.length} new post${
|
label={`View ${
|
||||||
this.state.backlogPosts.length > 1 ? "s" : ""
|
this.state.backlogPosts.length
|
||||||
|
} new post${
|
||||||
|
this.state.backlogPosts.length > 1
|
||||||
|
? "s"
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
color="primary"
|
color="primary"
|
||||||
className={classes.pageTopChip}
|
className={classes.pageTopChip}
|
||||||
|
@ -183,7 +187,13 @@ class LocalPage extends Component<any, ILocalPageState> {
|
||||||
{this.state.posts ? (
|
{this.state.posts ? (
|
||||||
<div>
|
<div>
|
||||||
{this.state.posts.map((post: Status) => {
|
{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 />
|
<br />
|
||||||
{this.state.viewDidLoad && !this.state.viewDidError ? (
|
{this.state.viewDidLoad && !this.state.viewDidError ? (
|
||||||
|
@ -205,7 +215,9 @@ class LocalPage extends Component<any, ILocalPageState> {
|
||||||
Something went wrong when loading this timeline.
|
Something went wrong when loading this timeline.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -213,7 +225,10 @@ class LocalPage extends Component<any, ILocalPageState> {
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|
|
@ -80,24 +80,39 @@ class MessagesPage extends Component<any, IMessagesState> {
|
||||||
<Paper className={classes.pageListConstraints}>
|
<Paper className={classes.pageListConstraints}>
|
||||||
<List>
|
<List>
|
||||||
{this.state.posts
|
{this.state.posts
|
||||||
? this.state.posts.map((message: Status) => {
|
? this.state.posts.map(
|
||||||
|
(message: Status) => {
|
||||||
return (
|
return (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<LinkableAvatar
|
<LinkableAvatar
|
||||||
to={`/profile/${message.account.id}`}
|
to={`/profile/${message.account.id}`}
|
||||||
alt={message.account.username}
|
alt={
|
||||||
src={message.account.avatar_static}
|
message
|
||||||
|
.account
|
||||||
|
.username
|
||||||
|
}
|
||||||
|
src={
|
||||||
|
message
|
||||||
|
.account
|
||||||
|
.avatar_static
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<PersonIcon />
|
<PersonIcon />
|
||||||
</LinkableAvatar>
|
</LinkableAvatar>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={
|
primary={
|
||||||
message.account.display_name ||
|
message.account
|
||||||
"@" + message.account.acct
|
.display_name ||
|
||||||
|
"@" +
|
||||||
|
message
|
||||||
|
.account
|
||||||
|
.acct
|
||||||
}
|
}
|
||||||
secondary={this.removeHTMLContent(message.content)}
|
secondary={this.removeHTMLContent(
|
||||||
|
message.content
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Tooltip title="View conversation">
|
<Tooltip title="View conversation">
|
||||||
|
@ -110,7 +125,8 @@ class MessagesPage extends Component<any, IMessagesState> {
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
})
|
}
|
||||||
|
)
|
||||||
: null}
|
: null}
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
@ -119,7 +135,10 @@ class MessagesPage extends Component<any, IMessagesState> {
|
||||||
) : null}
|
) : null}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,11 @@ class Missingno extends Component<any, any> {
|
||||||
The part of Hyperspace you're looking for isn't here.
|
The part of Hyperspace you're looking for isn't here.
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
<br />
|
||||||
<LinkableButton to="/home" color="primary" variant="contained">
|
<LinkableButton
|
||||||
|
to="/home"
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
Go back to home timeline
|
Go back to home timeline
|
||||||
</LinkableButton>
|
</LinkableButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -115,8 +115,14 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
let notifications = this.state.notifications;
|
let notifications = this.state.notifications;
|
||||||
if (notifications !== undefined && notifications.length > 0) {
|
if (notifications !== undefined && notifications.length > 0) {
|
||||||
notifications.forEach((notification: Notification) => {
|
notifications.forEach((notification: Notification) => {
|
||||||
if (notifications !== undefined && notification.id === id) {
|
if (
|
||||||
notifications.splice(notifications.indexOf(notification), 1);
|
notifications !== undefined &&
|
||||||
|
notification.id === id
|
||||||
|
) {
|
||||||
|
notifications.splice(
|
||||||
|
notifications.indexOf(notification),
|
||||||
|
1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -206,10 +212,16 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
primary={primary}
|
primary={primary}
|
||||||
secondary={
|
secondary={
|
||||||
<span>
|
<span>
|
||||||
<Typography color="textSecondary" className={classes.mobileOnly}>
|
<Typography
|
||||||
|
color="textSecondary"
|
||||||
|
className={classes.mobileOnly}
|
||||||
|
>
|
||||||
{secondary.slice(0, 35) + "..."}
|
{secondary.slice(0, 35) + "..."}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color="textSecondary" className={classes.desktopOnly}>
|
<Typography
|
||||||
|
color="textSecondary"
|
||||||
|
className={classes.desktopOnly}
|
||||||
|
>
|
||||||
{secondary}
|
{secondary}
|
||||||
</Typography>
|
</Typography>
|
||||||
</span>
|
</span>
|
||||||
|
@ -219,12 +231,18 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
{notif.type === "follow" ? (
|
{notif.type === "follow" ? (
|
||||||
<span>
|
<span>
|
||||||
<Tooltip title="View profile">
|
<Tooltip title="View profile">
|
||||||
<LinkableIconButton to={`/profile/${notif.account.id}`}>
|
<LinkableIconButton
|
||||||
|
to={`/profile/${notif.account.id}`}
|
||||||
|
>
|
||||||
<AssignmentIndIcon />
|
<AssignmentIndIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Follow account">
|
<Tooltip title="Follow account">
|
||||||
<IconButton onClick={() => this.followMember(notif.account)}>
|
<IconButton
|
||||||
|
onClick={() =>
|
||||||
|
this.followMember(notif.account)
|
||||||
|
}
|
||||||
|
>
|
||||||
<PersonAddIcon />
|
<PersonAddIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -232,7 +250,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
) : notif.status ? (
|
) : notif.status ? (
|
||||||
<span>
|
<span>
|
||||||
<Tooltip title="View conversation">
|
<Tooltip title="View conversation">
|
||||||
<LinkableIconButton to={`/conversation/${notif.status.id}`}>
|
<LinkableIconButton
|
||||||
|
to={`/conversation/${notif.status.id}`}
|
||||||
|
>
|
||||||
<ForumIcon />
|
<ForumIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -243,9 +263,12 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
notif.status.reblog
|
notif.status.reblog
|
||||||
? notif.status.reblog.id
|
? notif.status.reblog.id
|
||||||
: notif.status.id
|
: notif.status.id
|
||||||
}&visibility=${notif.status.visibility}&acct=${
|
}&visibility=${
|
||||||
|
notif.status.visibility
|
||||||
|
}&acct=${
|
||||||
notif.status.reblog
|
notif.status.reblog
|
||||||
? notif.status.reblog.account.acct
|
? notif.status.reblog.account
|
||||||
|
.acct
|
||||||
: notif.status.account.acct
|
: notif.status.account.acct
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
@ -256,7 +279,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
<Tooltip title="Remove notification">
|
<Tooltip title="Remove notification">
|
||||||
<IconButton onClick={() => this.removeNotification(notif.id)}>
|
<IconButton
|
||||||
|
onClick={() => this.removeNotification(notif.id)}
|
||||||
|
>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -269,12 +294,15 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
this.client
|
this.client
|
||||||
.post(`/accounts/${acct.id}/follow`)
|
.post(`/accounts/${acct.id}/follow`)
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
this.props.enqueueSnackbar("You are now following this account.");
|
this.props.enqueueSnackbar(
|
||||||
|
"You are now following this account."
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't follow account: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -284,7 +312,8 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
return (
|
return (
|
||||||
<div className={classes.pageLayoutConstraints}>
|
<div className={classes.pageLayoutConstraints}>
|
||||||
{this.state.viewDidLoad ? (
|
{this.state.viewDidLoad ? (
|
||||||
this.state.notifications && this.state.notifications.length > 0 ? (
|
this.state.notifications &&
|
||||||
|
this.state.notifications.length > 0 ? (
|
||||||
<div>
|
<div>
|
||||||
<ListSubheader>Recent notifications</ListSubheader>
|
<ListSubheader>Recent notifications</ListSubheader>
|
||||||
<Button
|
<Button
|
||||||
|
@ -299,7 +328,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
<List>
|
<List>
|
||||||
{this.state.notifications.map(
|
{this.state.notifications.map(
|
||||||
(notification: Notification) => {
|
(notification: Notification) => {
|
||||||
return this.createNotification(notification);
|
return this.createNotification(
|
||||||
|
notification
|
||||||
|
);
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
|
@ -309,8 +340,8 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
<div className={classes.pageLayoutEmptyTextConstraints}>
|
<div className={classes.pageLayoutEmptyTextConstraints}>
|
||||||
<Typography variant="h4">All clear!</Typography>
|
<Typography variant="h4">All clear!</Typography>
|
||||||
<Typography paragraph>
|
<Typography paragraph>
|
||||||
It looks like you have no notifications. Why not get the
|
It looks like you have no notifications. Why not
|
||||||
conversation going with a new post?
|
get the conversation going with a new post?
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -322,7 +353,9 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
Something went wrong when loading this timeline.
|
Something went wrong when loading this timeline.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -330,7 +363,10 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
@ -345,8 +381,8 @@ class NotificationsPage extends Component<any, INotificationsPageState> {
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
Are you sure you want to delete all notifications? This action
|
Are you sure you want to delete all notifications?
|
||||||
cannot be undone.
|
This action cannot be undone.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|
|
@ -90,7 +90,6 @@ export const styles = (theme: Theme) =>
|
||||||
pageHeroContent: {
|
pageHeroContent: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
paddingTop: 8,
|
paddingTop: 8,
|
||||||
textAlign: "center",
|
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
[theme.breakpoints.up("md")]: {
|
[theme.breakpoints.up("md")]: {
|
||||||
|
@ -254,7 +253,7 @@ export const styles = (theme: Theme) =>
|
||||||
height: 128
|
height: 128
|
||||||
},
|
},
|
||||||
instanceHeaderPaper: {
|
instanceHeaderPaper: {
|
||||||
height: 200,
|
height: 150,
|
||||||
backgroundPosition: "center",
|
backgroundPosition: "center",
|
||||||
backgroundRepeat: "no-repeat",
|
backgroundRepeat: "no-repeat",
|
||||||
backgroundSize: "cover",
|
backgroundSize: "cover",
|
||||||
|
@ -267,9 +266,11 @@ export const styles = (theme: Theme) =>
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
bottom: theme.spacing.unit,
|
bottom: theme.spacing.unit,
|
||||||
left: theme.spacing.unit * 2,
|
left: theme.spacing.unit * 2,
|
||||||
|
"& *": {
|
||||||
color: theme.palette.common.white,
|
color: theme.palette.common.white,
|
||||||
textShadow: `0 0 4px ${theme.palette.grey[700]}`,
|
textShadow: `0 0 4px ${theme.palette.grey[700]}`,
|
||||||
fontWeight: 600
|
fontWeight: 600
|
||||||
|
}
|
||||||
},
|
},
|
||||||
instanceToolbar: {
|
instanceToolbar: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
|
|
|
@ -135,7 +135,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
|
|
||||||
getRelationships() {
|
getRelationships() {
|
||||||
this.client
|
this.client
|
||||||
.get("/accounts/relationships", { id: this.props.match.params.profileId })
|
.get("/accounts/relationships", {
|
||||||
|
id: this.props.match.params.profileId
|
||||||
|
})
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
let relationship: Relationship = resp.data[0];
|
let relationship: Relationship = resp.data[0];
|
||||||
this.setState({ relationship });
|
this.setState({ relationship });
|
||||||
|
@ -189,7 +191,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.props.enqueueSnackbar("Reached end of posts", { variant: "error" });
|
this.props.enqueueSnackbar("Reached end of posts", {
|
||||||
|
variant: "error"
|
||||||
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
viewIsLoading: false,
|
viewIsLoading: false,
|
||||||
viewDidLoad: true
|
viewDidLoad: true
|
||||||
|
@ -234,12 +238,15 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
let relationship: Relationship = resp.data;
|
let relationship: Relationship = resp.data;
|
||||||
this.setState({ relationship });
|
this.setState({ relationship });
|
||||||
this.props.enqueueSnackbar("You are now following this account.");
|
this.props.enqueueSnackbar(
|
||||||
|
"You are now following this account."
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't follow account: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -283,12 +290,15 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
let relationship: Relationship = resp.data;
|
let relationship: Relationship = resp.data;
|
||||||
this.setState({ relationship });
|
this.setState({ relationship });
|
||||||
this.props.enqueueSnackbar("You are now blocking this account.");
|
this.props.enqueueSnackbar(
|
||||||
|
"You are now blocking this account."
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar("Couldn't block account: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't block account: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -314,7 +324,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
title={
|
title={
|
||||||
this.isItMe()
|
this.isItMe()
|
||||||
? "You can't follow yourself."
|
? "You can't follow yourself."
|
||||||
: this.state.relationship && this.state.relationship.following
|
: this.state.relationship &&
|
||||||
|
this.state.relationship.following
|
||||||
? "Unfollow"
|
? "Unfollow"
|
||||||
: "Follow"
|
: "Follow"
|
||||||
}
|
}
|
||||||
|
@ -337,7 +348,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
<Tooltip title={"Send a message or post"}>
|
<Tooltip title={"Send a message or post"}>
|
||||||
<LinkableIconButton
|
<LinkableIconButton
|
||||||
to={`/compose?acct=${
|
to={`/compose?acct=${
|
||||||
this.state.account ? this.state.account.acct : ""
|
this.state.account
|
||||||
|
? this.state.account.acct
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
color={"inherit"}
|
color={"inherit"}
|
||||||
>
|
>
|
||||||
|
@ -346,7 +359,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
this.state.relationship && this.state.relationship.blocking
|
this.state.relationship &&
|
||||||
|
this.state.relationship.blocking
|
||||||
? "Unblock this account"
|
? "Unblock this account"
|
||||||
: "Block this account"
|
: "Block this account"
|
||||||
}
|
}
|
||||||
|
@ -356,7 +370,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
disabled={this.isItMe()}
|
disabled={this.isItMe()}
|
||||||
onClick={() => this.toggleBlockDialog()}
|
onClick={() => this.toggleBlockDialog()}
|
||||||
>
|
>
|
||||||
{this.state.relationship && this.state.relationship.blocking ? (
|
{this.state.relationship &&
|
||||||
|
this.state.relationship.blocking ? (
|
||||||
<AccountHeartIcon />
|
<AccountHeartIcon />
|
||||||
) : (
|
) : (
|
||||||
<AccountRemoveIcon />
|
<AccountRemoveIcon />
|
||||||
|
@ -365,7 +380,11 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Open in web">
|
<Tooltip title="Open in web">
|
||||||
<IconButton
|
<IconButton
|
||||||
href={this.state.account ? this.state.account.url : ""}
|
href={
|
||||||
|
this.state.account
|
||||||
|
? this.state.account.url
|
||||||
|
: ""
|
||||||
|
}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel={"nofollower noreferrer noopener"}
|
rel={"nofollower noreferrer noopener"}
|
||||||
color={"inherit"}
|
color={"inherit"}
|
||||||
|
@ -384,7 +403,11 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
<div className={classes.profileContent}>
|
<div className={classes.profileContent}>
|
||||||
<Avatar
|
<Avatar
|
||||||
className={classes.profileAvatar}
|
className={classes.profileAvatar}
|
||||||
src={this.state.account ? this.state.account.avatar : ""}
|
src={
|
||||||
|
this.state.account
|
||||||
|
? this.state.account.avatar
|
||||||
|
: ""
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<div className={classes.profileUserBox}>
|
<div className={classes.profileUserBox}>
|
||||||
<Typography
|
<Typography
|
||||||
|
@ -394,7 +417,8 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
__html: this.state.account
|
__html: this.state.account
|
||||||
? this.state.account.display_name
|
? this.state.account.display_name
|
||||||
? emojifyString(
|
? emojifyString(
|
||||||
this.state.account.display_name,
|
this.state.account
|
||||||
|
.display_name,
|
||||||
this.state.account.emojis,
|
this.state.account.emojis,
|
||||||
classes.pageProfileNameEmoji
|
classes.pageProfileNameEmoji
|
||||||
)
|
)
|
||||||
|
@ -404,7 +428,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
className={classes.pageProfileNameEmoji}
|
className={classes.pageProfileNameEmoji}
|
||||||
/>
|
/>
|
||||||
<Typography variant="caption" color="inherit">
|
<Typography variant="caption" color="inherit">
|
||||||
{this.state.account ? "@" + this.state.account.acct : ""}
|
{this.state.account
|
||||||
|
? "@" + this.state.account.acct
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography paragraph color="inherit">
|
<Typography paragraph color="inherit">
|
||||||
{this.state.account
|
{this.state.account
|
||||||
|
@ -414,11 +440,17 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
: "No bio available."}
|
: "No bio available."}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography color={"inherit"}>
|
<Typography color={"inherit"}>
|
||||||
{this.state.account ? this.state.account.followers_count : 0}{" "}
|
{this.state.account
|
||||||
|
? this.state.account.followers_count
|
||||||
|
: 0}{" "}
|
||||||
followers |{" "}
|
followers |{" "}
|
||||||
{this.state.account ? this.state.account.following_count : 0}{" "}
|
{this.state.account
|
||||||
|
? this.state.account.following_count
|
||||||
|
: 0}{" "}
|
||||||
following |{" "}
|
following |{" "}
|
||||||
{this.state.account ? this.state.account.statuses_count : 0}{" "}
|
{this.state.account
|
||||||
|
? this.state.account.statuses_count
|
||||||
|
: 0}{" "}
|
||||||
posts
|
posts
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
@ -432,7 +464,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
Something went wrong when loading this profile.
|
Something went wrong when loading this profile.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -441,15 +475,26 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
{this.state.posts ? (
|
{this.state.posts ? (
|
||||||
<div>
|
<div>
|
||||||
{this.state.posts.map((post: Status) => {
|
{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 />
|
<br />
|
||||||
{this.state.viewDidLoad && !this.state.viewDidError ? (
|
{this.state.viewDidLoad &&
|
||||||
|
!this.state.viewDidError ? (
|
||||||
<div
|
<div
|
||||||
style={{ textAlign: "center" }}
|
style={{ textAlign: "center" }}
|
||||||
onClick={() => this.loadMoreTimelinePieces()}
|
onClick={() =>
|
||||||
|
this.loadMoreTimelinePieces()
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Button variant="contained">Load more</Button>
|
<Button variant="contained">
|
||||||
|
Load more
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -458,7 +503,10 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
@ -472,8 +520,9 @@ class ProfilePage extends Component<any, IProfilePageState> {
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
Are you sure you want to block this person? You won't see their
|
Are you sure you want to block this person? You
|
||||||
posts on your home feed, local timeline, or public timeline.
|
won't see their posts on your home feed, local
|
||||||
|
timeline, or public timeline.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|
|
@ -167,8 +167,12 @@ class PublicPage extends Component<any, IPublicPageState> {
|
||||||
<ArrowUpwardIcon />
|
<ArrowUpwardIcon />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
}
|
}
|
||||||
label={`View ${this.state.backlogPosts.length} new post${
|
label={`View ${
|
||||||
this.state.backlogPosts.length > 1 ? "s" : ""
|
this.state.backlogPosts.length
|
||||||
|
} new post${
|
||||||
|
this.state.backlogPosts.length > 1
|
||||||
|
? "s"
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
color="primary"
|
color="primary"
|
||||||
className={classes.pageTopChip}
|
className={classes.pageTopChip}
|
||||||
|
@ -182,7 +186,13 @@ class PublicPage extends Component<any, IPublicPageState> {
|
||||||
{this.state.posts ? (
|
{this.state.posts ? (
|
||||||
<div>
|
<div>
|
||||||
{this.state.posts.map((post: Status) => {
|
{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 />
|
<br />
|
||||||
{this.state.viewDidLoad && !this.state.viewDidError ? (
|
{this.state.viewDidLoad && !this.state.viewDidError ? (
|
||||||
|
@ -204,7 +214,9 @@ class PublicPage extends Component<any, IPublicPageState> {
|
||||||
Something went wrong when loading this timeline.
|
Something went wrong when loading this timeline.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -212,7 +224,10 @@ class PublicPage extends Component<any, IPublicPageState> {
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|
|
@ -96,23 +96,31 @@ class RecommendationsPage extends Component<
|
||||||
this.client
|
this.client
|
||||||
.post(`/accounts/${acct.id}/follow`)
|
.post(`/accounts/${acct.id}/follow`)
|
||||||
.then((resp: any) => {
|
.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) => {
|
this.client.del(`/suggestions/${acct.id}`).then((resp: any) => {
|
||||||
let followSuggestions = this.state.followSuggestions;
|
let followSuggestions = this.state.followSuggestions;
|
||||||
if (followSuggestions) {
|
if (followSuggestions) {
|
||||||
followSuggestions.forEach((suggestion: Account, index: number) => {
|
followSuggestions.forEach(
|
||||||
if (followSuggestions && suggestion.id === acct.id) {
|
(suggestion: Account, index: number) => {
|
||||||
|
if (
|
||||||
|
followSuggestions &&
|
||||||
|
suggestion.id === acct.id
|
||||||
|
) {
|
||||||
followSuggestions.splice(index, 1);
|
followSuggestions.splice(index, 1);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
this.setState({ followSuggestions });
|
this.setState({ followSuggestions });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't follow account: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -123,16 +131,20 @@ class RecommendationsPage extends Component<
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
let requestedFollows = this.state.requestedFollows;
|
let requestedFollows = this.state.requestedFollows;
|
||||||
if (requestedFollows) {
|
if (requestedFollows) {
|
||||||
requestedFollows.forEach((request: Account, index: number) => {
|
requestedFollows.forEach(
|
||||||
|
(request: Account, index: number) => {
|
||||||
if (requestedFollows && request.id === acct.id) {
|
if (requestedFollows && request.id === acct.id) {
|
||||||
requestedFollows.splice(index, 1);
|
requestedFollows.splice(index, 1);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
this.setState({ requestedFollows });
|
this.setState({ requestedFollows });
|
||||||
|
|
||||||
let verb: string = type;
|
let verb: string = type;
|
||||||
verb === "authorize" ? (verb = "authorized") : (verb = "rejected");
|
verb === "authorize"
|
||||||
|
? (verb = "authorized")
|
||||||
|
: (verb = "rejected");
|
||||||
this.props.enqueueSnackbar(`You have ${verb} this request.`);
|
this.props.enqueueSnackbar(`You have ${verb} this request.`);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
|
@ -152,25 +164,34 @@ class RecommendationsPage extends Component<
|
||||||
<Paper className={classes.pageListConstraints}>
|
<Paper className={classes.pageListConstraints}>
|
||||||
<List>
|
<List>
|
||||||
{this.state.requestedFollows
|
{this.state.requestedFollows
|
||||||
? this.state.requestedFollows.map((request: Account) => {
|
? this.state.requestedFollows.map(
|
||||||
|
(request: Account) => {
|
||||||
return (
|
return (
|
||||||
<ListItem key={request.id}>
|
<ListItem key={request.id}>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<LinkableAvatar
|
<LinkableAvatar
|
||||||
to={`/profile/${request.id}`}
|
to={`/profile/${request.id}`}
|
||||||
alt={request.username}
|
alt={request.username}
|
||||||
src={request.avatar_static}
|
src={
|
||||||
|
request.avatar_static
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={request.display_name || request.acct}
|
primary={
|
||||||
|
request.display_name ||
|
||||||
|
request.acct
|
||||||
|
}
|
||||||
secondary={request.acct}
|
secondary={request.acct}
|
||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Tooltip title="Accept request">
|
<Tooltip title="Accept request">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
this.handleFollowRequest(request, "authorize")
|
this.handleFollowRequest(
|
||||||
|
request,
|
||||||
|
"authorize"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CheckIcon />
|
<CheckIcon />
|
||||||
|
@ -179,21 +200,27 @@ class RecommendationsPage extends Component<
|
||||||
<Tooltip title="Reject request">
|
<Tooltip title="Reject request">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
this.handleFollowRequest(request, "reject")
|
this.handleFollowRequest(
|
||||||
|
request,
|
||||||
|
"reject"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="View profile">
|
<Tooltip title="View profile">
|
||||||
<LinkableIconButton to={`/profile/${request.id}`}>
|
<LinkableIconButton
|
||||||
|
to={`/profile/${request.id}`}
|
||||||
|
>
|
||||||
<AccountCircleIcon />
|
<AccountCircleIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
})
|
}
|
||||||
|
)
|
||||||
: null}
|
: null}
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
@ -210,29 +237,41 @@ class RecommendationsPage extends Component<
|
||||||
<Paper className={classes.pageListConstraints}>
|
<Paper className={classes.pageListConstraints}>
|
||||||
<List>
|
<List>
|
||||||
{this.state.followSuggestions
|
{this.state.followSuggestions
|
||||||
? this.state.followSuggestions.map((suggestion: Account) => {
|
? this.state.followSuggestions.map(
|
||||||
|
(suggestion: Account) => {
|
||||||
return (
|
return (
|
||||||
<ListItem key={suggestion.id}>
|
<ListItem key={suggestion.id}>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<LinkableAvatar
|
<LinkableAvatar
|
||||||
to={`/profile/${suggestion.id}`}
|
to={`/profile/${suggestion.id}`}
|
||||||
alt={suggestion.username}
|
alt={suggestion.username}
|
||||||
src={suggestion.avatar_static}
|
src={
|
||||||
|
suggestion.avatar_static
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={suggestion.display_name || suggestion.acct}
|
primary={
|
||||||
|
suggestion.display_name ||
|
||||||
|
suggestion.acct
|
||||||
|
}
|
||||||
secondary={suggestion.acct}
|
secondary={suggestion.acct}
|
||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Tooltip title="View profile">
|
<Tooltip title="View profile">
|
||||||
<LinkableIconButton to={`/profile/${suggestion.id}`}>
|
<LinkableIconButton
|
||||||
|
to={`/profile/${suggestion.id}`}
|
||||||
|
>
|
||||||
<AssignmentIndIcon />
|
<AssignmentIndIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Follow">
|
<Tooltip title="Follow">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => this.followMember(suggestion)}
|
onClick={() =>
|
||||||
|
this.followMember(
|
||||||
|
suggestion
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<PersonAddIcon />
|
<PersonAddIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -240,7 +279,8 @@ class RecommendationsPage extends Component<
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
})
|
}
|
||||||
|
)
|
||||||
: null}
|
: null}
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
@ -259,7 +299,11 @@ class RecommendationsPage extends Component<
|
||||||
this.state.requestedFollows.length > 0 ? (
|
this.state.requestedFollows.length > 0 ? (
|
||||||
this.showFollowRequests()
|
this.showFollowRequests()
|
||||||
) : (
|
) : (
|
||||||
<div className={classes.pageLayoutEmptyTextConstraints}>
|
<div
|
||||||
|
className={
|
||||||
|
classes.pageLayoutEmptyTextConstraints
|
||||||
|
}
|
||||||
|
>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
You don't have any follow requests.
|
You don't have any follow requests.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -272,13 +316,17 @@ class RecommendationsPage extends Component<
|
||||||
this.state.followSuggestions.length > 0 ? (
|
this.state.followSuggestions.length > 0 ? (
|
||||||
this.showFollowSuggestions()
|
this.showFollowSuggestions()
|
||||||
) : (
|
) : (
|
||||||
<div className={classes.pageLayoutEmptyTextConstraints}>
|
<div
|
||||||
|
className={
|
||||||
|
classes.pageLayoutEmptyTextConstraints
|
||||||
|
}
|
||||||
|
>
|
||||||
<Typography variant="h5">
|
<Typography variant="h5">
|
||||||
We don't have any suggestions for you.
|
We don't have any suggestions for you.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography paragraph>
|
<Typography paragraph>
|
||||||
Why not interact with the fediverse a bit by creating a new
|
Why not interact with the fediverse a bit by
|
||||||
post?
|
creating a new post?
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -291,7 +339,9 @@ class RecommendationsPage extends Component<
|
||||||
Something went wrong when loading this timeline.
|
Something went wrong when loading this timeline.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -299,7 +349,10 @@ class RecommendationsPage extends Component<
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|
|
@ -179,12 +179,15 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
client
|
client
|
||||||
.post(`/accounts/${acct.id}/follow`)
|
.post(`/accounts/${acct.id}/follow`)
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
this.props.enqueueSnackbar("You are now following this account.");
|
this.props.enqueueSnackbar(
|
||||||
|
"You are now following this account."
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.enqueueSnackbar("Couldn't follow account: " + err.name, {
|
this.props.enqueueSnackbar(
|
||||||
variant: "error"
|
"Couldn't follow account: " + err.name,
|
||||||
});
|
{ variant: "error" }
|
||||||
|
);
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -195,10 +198,12 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
<div>
|
<div>
|
||||||
<ListSubheader>Accounts</ListSubheader>
|
<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}>
|
<Paper className={classes.pageListConstraints}>
|
||||||
<List>
|
<List>
|
||||||
{this.state.results.accounts.map((acct: Account) => {
|
{this.state.results.accounts.map(
|
||||||
|
(acct: Account) => {
|
||||||
return (
|
return (
|
||||||
<ListItem key={acct.id}>
|
<ListItem key={acct.id}>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
|
@ -209,18 +214,27 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
/>
|
/>
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={acct.display_name || acct.acct}
|
primary={
|
||||||
|
acct.display_name ||
|
||||||
|
acct.acct
|
||||||
|
}
|
||||||
secondary={acct.acct}
|
secondary={acct.acct}
|
||||||
/>
|
/>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<Tooltip title="View profile">
|
<Tooltip title="View profile">
|
||||||
<LinkableIconButton to={`/profile/${acct.id}`}>
|
<LinkableIconButton
|
||||||
|
to={`/profile/${acct.id}`}
|
||||||
|
>
|
||||||
<AssignmentIndIcon />
|
<AssignmentIndIcon />
|
||||||
</LinkableIconButton>
|
</LinkableIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Follow">
|
<Tooltip title="Follow">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => this.followMemberFromQuery(acct)}
|
onClick={() =>
|
||||||
|
this.followMemberFromQuery(
|
||||||
|
acct
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<PersonAddIcon />
|
<PersonAddIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -228,7 +242,8 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -253,7 +268,13 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
{this.state.results ? (
|
{this.state.results ? (
|
||||||
this.state.results.statuses.length > 0 ? (
|
this.state.results.statuses.length > 0 ? (
|
||||||
this.state.results.statuses.map((post: Status) => {
|
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
|
<Typography
|
||||||
|
@ -276,7 +297,13 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
{this.state.tagResults ? (
|
{this.state.tagResults ? (
|
||||||
this.state.tagResults.length > 0 ? (
|
this.state.tagResults.length > 0 ? (
|
||||||
this.state.tagResults.map((post: Status) => {
|
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
|
<Typography
|
||||||
|
@ -310,7 +337,9 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
Something went wrong when loading this timeline.
|
Something went wrong when loading this timeline.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.state.viewDidErrorCode ? this.state.viewDidErrorCode : ""}
|
{this.state.viewDidErrorCode
|
||||||
|
? this.state.viewDidErrorCode
|
||||||
|
: ""}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -318,7 +347,10 @@ class SearchPage extends Component<any, ISearchPageState> {
|
||||||
)}
|
)}
|
||||||
{this.state.viewIsLoading ? (
|
{this.state.viewIsLoading ? (
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<CircularProgress className={classes.progress} color="primary" />
|
<CircularProgress
|
||||||
|
className={classes.progress}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
|
|
|
@ -46,7 +46,6 @@ import {
|
||||||
} from "../utilities/themes";
|
} from "../utilities/themes";
|
||||||
import { Visibility } from "../types/Visibility";
|
import { Visibility } from "../types/Visibility";
|
||||||
import { LinkableButton } from "../interfaces/overrides";
|
import { LinkableButton } from "../interfaces/overrides";
|
||||||
import { Config } from "../types/Config";
|
|
||||||
|
|
||||||
import OpenInNewIcon from "@material-ui/icons/OpenInNew";
|
import OpenInNewIcon from "@material-ui/icons/OpenInNew";
|
||||||
import DevicesIcon from "@material-ui/icons/Devices";
|
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 BellAlertIcon from "mdi-material-ui/BellAlert";
|
||||||
import RefreshIcon from "@material-ui/icons/Refresh";
|
import RefreshIcon from "@material-ui/icons/Refresh";
|
||||||
import UndoIcon from "@material-ui/icons/Undo";
|
import UndoIcon from "@material-ui/icons/Undo";
|
||||||
import DomainDisablbedIcon from "@material-ui/icons/DomainDisabled";
|
import { Config } from "../types/Config";
|
||||||
|
|
||||||
interface ISettingsState {
|
interface ISettingsState {
|
||||||
darkModeEnabled: boolean;
|
darkModeEnabled: boolean;
|
||||||
|
@ -500,20 +499,6 @@ class SettingsPage extends Component<any, ISettingsState> {
|
||||||
<LinkableButton to="/you">Edit</LinkableButton>
|
<LinkableButton to="/you">Edit</LinkableButton>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</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>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<MastodonIcon color="action" />
|
<MastodonIcon color="action" />
|
||||||
|
|
|
@ -17,11 +17,7 @@ import {
|
||||||
import { styles } from "./WelcomePage.styles";
|
import { styles } from "./WelcomePage.styles";
|
||||||
import Mastodon from "megalodon";
|
import Mastodon from "megalodon";
|
||||||
import { SaveClientSession } from "../types/SessionData";
|
import { SaveClientSession } from "../types/SessionData";
|
||||||
import {
|
import { createHyperspaceApp, getRedirectAddress } from "../utilities/login";
|
||||||
createHyperspaceApp,
|
|
||||||
getRedirectAddress,
|
|
||||||
inDisallowedDomains
|
|
||||||
} from "../utilities/login";
|
|
||||||
import { parseUrl } from "query-string";
|
import { parseUrl } from "query-string";
|
||||||
import { getConfig } from "../utilities/settings";
|
import { getConfig } from "../utilities/settings";
|
||||||
import { isDarwinApp } from "../utilities/desktop";
|
import { isDarwinApp } from "../utilities/desktop";
|
||||||
|
@ -83,17 +79,9 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
|
||||||
let config: Config = result;
|
let config: Config = result;
|
||||||
if (result.location === "dynamic") {
|
if (result.location === "dynamic") {
|
||||||
console.warn(
|
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({
|
this.setState({
|
||||||
logoUrl: config.branding
|
logoUrl: config.branding
|
||||||
? result.branding.logo
|
? result.branding.logo
|
||||||
|
@ -322,19 +310,8 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
|
||||||
if (this.state.user.includes("@")) {
|
if (this.state.user.includes("@")) {
|
||||||
if (this.state.federates && this.state.federates === true) {
|
if (this.state.federates && this.state.federates === true) {
|
||||||
let baseUrl = this.state.user.split("@")[1];
|
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
|
axios
|
||||||
.get(
|
.get("https://" + baseUrl + "/api/v1/timelines/public")
|
||||||
"https://" +
|
|
||||||
baseUrl +
|
|
||||||
"/api/v1/timelines/public"
|
|
||||||
)
|
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
let userInputError = true;
|
let userInputError = true;
|
||||||
let userInputErrorMessage =
|
let userInputErrorMessage =
|
||||||
|
@ -345,7 +322,6 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else if (
|
} else if (
|
||||||
this.state.user.includes(
|
this.state.user.includes(
|
||||||
this.state.registerBase
|
this.state.registerBase
|
||||||
|
@ -726,8 +702,7 @@ class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
|
||||||
{this.state.brandName
|
{this.state.brandName
|
||||||
? this.state.brandName
|
? this.state.brandName
|
||||||
: "Hypersapce"}{" "}
|
: "Hypersapce"}{" "}
|
||||||
v.
|
v.{this.state.version}{" "}
|
||||||
{this.state.version}{" "}
|
|
||||||
{this.state.brandName &&
|
{this.state.brandName &&
|
||||||
this.state.brandName !== "Hyperspace"
|
this.state.brandName !== "Hyperspace"
|
||||||
? "(Hyperspace-like)"
|
? "(Hyperspace-like)"
|
||||||
|
|
|
@ -71,9 +71,14 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
.then((acct: any) => {
|
.then((acct: any) => {
|
||||||
let currentAccount: Account = acct.data;
|
let currentAccount: Account = acct.data;
|
||||||
this.setState({ currentAccount });
|
this.setState({ currentAccount });
|
||||||
localStorage.setItem("account", JSON.stringify(currentAccount));
|
localStorage.setItem(
|
||||||
|
"account",
|
||||||
|
JSON.stringify(currentAccount)
|
||||||
|
);
|
||||||
this.props.closeSnackbar("persistAvatar");
|
this.props.closeSnackbar("persistAvatar");
|
||||||
this.props.enqueueSnackbar("Avatar updated successfully.");
|
this.props.enqueueSnackbar(
|
||||||
|
"Avatar updated successfully."
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.closeSnackbar("persistAvatar");
|
this.props.closeSnackbar("persistAvatar");
|
||||||
|
@ -85,7 +90,9 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.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) => {
|
.then((acct: any) => {
|
||||||
let currentAccount: Account = acct.data;
|
let currentAccount: Account = acct.data;
|
||||||
this.setState({ currentAccount });
|
this.setState({ currentAccount });
|
||||||
localStorage.setItem("account", JSON.stringify(currentAccount));
|
localStorage.setItem(
|
||||||
|
"account",
|
||||||
|
JSON.stringify(currentAccount)
|
||||||
|
);
|
||||||
this.props.closeSnackbar("persistHeader");
|
this.props.closeSnackbar("persistHeader");
|
||||||
this.props.enqueueSnackbar("Header updated successfully.");
|
this.props.enqueueSnackbar(
|
||||||
|
"Header updated successfully."
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
this.props.closeSnackbar("persistHeader");
|
this.props.closeSnackbar("persistHeader");
|
||||||
|
@ -121,7 +133,9 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err: Error) => {
|
.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 });
|
this.setState({ newDisplayName: name });
|
||||||
}
|
}
|
||||||
changeBio() {
|
changeBio() {
|
||||||
|
@ -198,15 +212,27 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
backgroundImage: `url("${this.state.currentAccount.header_static}")`
|
backgroundImage: `url("${this.state.currentAccount.header_static}")`
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className={classes.pageHeroContent}>
|
<div className={classes.profileContent}>
|
||||||
|
<br />
|
||||||
<Avatar
|
<Avatar
|
||||||
className={classes.pageProfileAvatar}
|
className={classes.profileAvatar}
|
||||||
src={this.state.currentAccount.avatar_static}
|
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
|
Edit your profile
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
<Typography color="inherit">
|
||||||
|
Change information such as your display name,
|
||||||
|
bio, and images used here.
|
||||||
|
</Typography>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
className={classes.pageProfileFollowButton}
|
className={classes.pageProfileFollowButton}
|
||||||
|
@ -223,7 +249,7 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
Change Header
|
Change Header
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.pageContentLayoutConstraints}>
|
<div className={classes.pageContentLayoutConstraints}>
|
||||||
|
@ -234,14 +260,16 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
<br />
|
<br />
|
||||||
<TextField
|
<TextField
|
||||||
className={classes.TextField}
|
className={classes.TextField}
|
||||||
defaultValue={this.state.currentAccount.display_name}
|
defaultValue={
|
||||||
|
this.state.currentAccount.display_name
|
||||||
|
}
|
||||||
rowsMax="1"
|
rowsMax="1"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={(event: any) =>
|
onChange={(event: any) =>
|
||||||
this.updateDisplayname(event.target.value)
|
this.updateDisplayName(event.target.value)
|
||||||
}
|
}
|
||||||
></TextField>
|
/>
|
||||||
<div style={{ textAlign: "right" }}>
|
<div style={{ textAlign: "right" }}>
|
||||||
<Button
|
<Button
|
||||||
className={classes.pageProfileFollowButton}
|
className={classes.pageProfileFollowButton}
|
||||||
|
@ -262,7 +290,9 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
className={classes.TextField}
|
className={classes.TextField}
|
||||||
defaultValue={
|
defaultValue={
|
||||||
this.state.currentAccount.note
|
this.state.currentAccount.note
|
||||||
? this.removeHTMLContent(this.state.currentAccount.note)
|
? this.removeHTMLContent(
|
||||||
|
this.state.currentAccount.note
|
||||||
|
)
|
||||||
: "Tell a little bit about yourself"
|
: "Tell a little bit about yourself"
|
||||||
}
|
}
|
||||||
multiline
|
multiline
|
||||||
|
@ -270,8 +300,10 @@ class You extends Component<IYouProps, IYouState> {
|
||||||
rows="2"
|
rows="2"
|
||||||
rowsMax="5"
|
rowsMax="5"
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={(event: any) => this.updateBio(event.target.value)}
|
onChange={(event: any) =>
|
||||||
></TextField>
|
this.updateBio(event.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
<div style={{ textAlign: "right" }}>
|
<div style={{ textAlign: "right" }}>
|
||||||
<Button
|
<Button
|
||||||
className={classes.pageProfileFollowButton}
|
className={classes.pageProfileFollowButton}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import Mastodon from "megalodon";
|
import Mastodon from "megalodon";
|
||||||
|
|
||||||
export function userLoggedIn(): boolean {
|
export function userLoggedIn(): boolean {
|
||||||
if (localStorage.getItem("baseurl") && localStorage.getItem("access_token")) {
|
if (
|
||||||
|
localStorage.getItem("baseurl") &&
|
||||||
|
localStorage.getItem("access_token")
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -55,13 +55,3 @@ export function getRedirectAddress(
|
||||||
return type;
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -135,7 +135,8 @@ export async function getConfig(): Promise<Config | undefined> {
|
||||||
return config;
|
return config;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(
|
console.error(
|
||||||
"Couldn't configure Hyperspace with the config file. Reason: " + err.name
|
"Couldn't configure Hyperspace with the config file. Reason: " +
|
||||||
|
err.name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue