diff --git a/src/components/common/ServerHeader.tsx b/src/components/common/ServerHeader.tsx
new file mode 100644
index 00000000..e2a89df8
--- /dev/null
+++ b/src/components/common/ServerHeader.tsx
@@ -0,0 +1,39 @@
+import Header from "../ui/Header";
+import styled from "styled-components";
+import { Link } from "react-router-dom";
+import IconButton from "../ui/IconButton";
+import { Settings } from "@styled-icons/feather";
+import { Server } from "revolt.js/dist/api/objects";
+import { ServerPermission } from "revolt.js/dist/api/permissions";
+import { HookContext, useServerPermission } from "../../context/revoltjs/hooks";
+
+interface Props {
+ server: Server,
+ ctx: HookContext
+}
+
+const ServerName = styled.div`
+ flex-grow: 1;
+`;
+
+export default function ServerHeader({ server, ctx }: Props) {
+ const permissions = useServerPermission(server._id, ctx);
+ const bannerURL = ctx.client.servers.getBannerURL(server._id, { width: 480 }, true);
+
+ return (
+
+
+ { server.name }
+
+ { (permissions & ServerPermission.ManageServer) > 0 &&
+
+
+
+
+
+
}
+
+ )
+}
diff --git a/src/components/navigation/left/ServerSidebar.tsx b/src/components/navigation/left/ServerSidebar.tsx
index f4cae5fd..b84bb69c 100644
--- a/src/components/navigation/left/ServerSidebar.tsx
+++ b/src/components/navigation/left/ServerSidebar.tsx
@@ -14,6 +14,7 @@ import { connectState } from "../../../redux/connector";
import PaintCounter from "../../../lib/PaintCounter";
import styled from "styled-components";
import { attachContextMenu } from 'preact-context-menu';
+import ServerHeader from "../../common/ServerHeader";
interface Props {
unreads: Unreads;
@@ -45,7 +46,6 @@ function ServerSidebar(props: Props & WithDispatcher) {
const server = useServer(server_id, ctx);
if (!server) return ;
- const permissions = useServerPermission(server._id, ctx);
const channels = (useChannels(server.channels, ctx)
.filter(entry => typeof entry !== 'undefined') as Readonly[])
.map(x => mapChannelWithUnread(x, props.unreads));
@@ -55,16 +55,7 @@ function ServerSidebar(props: Props & WithDispatcher) {
return (
-
-
- { server.name }
-
- { (permissions & ServerPermission.ManageServer) > 0 &&
- {/**/}
-
- {/**/}
-
}
-
+
{channels.map(entry => {
diff --git a/src/pages/Open.tsx b/src/pages/Open.tsx
new file mode 100644
index 00000000..7ee8120c
--- /dev/null
+++ b/src/pages/Open.tsx
@@ -0,0 +1,72 @@
+import { Text } from "preact-i18n";
+import Header from "../components/ui/Header";
+import { useContext, useEffect } from "preact/hooks";
+import { useHistory, useParams } from "react-router-dom";
+import { useIntermediate } from "../context/intermediate/Intermediate";
+import { useChannels, useForceUpdate, useUser } from "../context/revoltjs/hooks";
+import { AppContext, ClientStatus, StatusContext } from "../context/revoltjs/RevoltClient";
+
+export default function Open() {
+ const history = useHistory();
+ const client = useContext(AppContext);
+ const status = useContext(StatusContext);
+ const { id } = useParams<{ id: string }>();
+ const { openScreen } = useIntermediate();
+
+ if (status !== ClientStatus.ONLINE) {
+ return (
+
+ );
+ }
+
+ const ctx = useForceUpdate();
+ const channels = useChannels(undefined, ctx);
+ const user = useUser(id, ctx);
+
+ useEffect(() => {
+ if (id === "saved") {
+ for (const channel of channels) {
+ if (channel?.channel_type === "SavedMessages") {
+ history.push(`/channel/${channel._id}`);
+ return;
+ }
+ }
+
+ client.users
+ .openDM(client.user?._id as string)
+ .then(channel => history.push(`/channel/${channel?._id}`))
+ .catch(error => openScreen({ id: "error", error }));
+
+ return;
+ }
+
+ if (user) {
+ const channel: string | undefined = channels.find(
+ channel =>
+ channel?.channel_type === "DirectMessage" &&
+ channel.recipients.includes(id)
+ )?._id;
+
+ if (channel) {
+ history.push(`/channel/${channel}`);
+ } else {
+ client.users
+ .openDM(id)
+ .then(channel => history.push(`/channel/${channel?._id}`))
+ .catch(error => openScreen({ id: "error", error }));
+ }
+
+ return;
+ }
+
+ history.push("/");
+ }, []);
+
+ return (
+
+ );
+}
diff --git a/src/pages/RevoltApp.tsx b/src/pages/RevoltApp.tsx
index f20c2031..53400ce8 100644
--- a/src/pages/RevoltApp.tsx
+++ b/src/pages/RevoltApp.tsx
@@ -13,7 +13,9 @@ import LeftSidebar from "../components/navigation/LeftSidebar";
import RightSidebar from "../components/navigation/RightSidebar";
import BottomNavigation from "../components/navigation/BottomNavigation";
+import Open from "./Open";
import Home from './home/Home';
+import Invite from "./invite/Invite";
import Friends from "./friends/Friends";
import Channel from "./channels/Channel";
import Settings from './settings/Settings';
@@ -64,6 +66,8 @@ export default function App() {
+
+
@@ -75,15 +79,3 @@ export default function App() {
);
};
-
-/**
- *
- *
-
-
-
-
- {/*
-
-
- */
diff --git a/src/pages/invite/Invite.module.scss b/src/pages/invite/Invite.module.scss
new file mode 100644
index 00000000..58814516
--- /dev/null
+++ b/src/pages/invite/Invite.module.scss
@@ -0,0 +1,75 @@
+.invite {
+ height: 100%;
+ display: flex;
+ color: white;
+ user-select: none;
+ align-items: center;
+ flex-direction: column;
+ background-size: cover;
+ justify-content: center;
+ background-position: center;
+
+ * {
+ overflow: visible;
+ }
+
+ .icon {
+ width: 64px;
+ z-index: 100;
+ text-align: left;
+ position: relative;
+
+ > * {
+ top: -32px;
+ position: absolute;
+ }
+ }
+
+ .leave {
+ top: 8px;
+ left: 8px;
+ cursor: pointer;
+ position: fixed;
+ }
+
+ .details {
+ text-align: center;
+ border-radius: 3px;
+ align-self: center;
+ padding: 32px 16px 16px 16px;
+ background: rgba(0, 0, 0, 0.6);
+
+ h1 {
+ margin: 0;
+ font-weight: 500;
+ }
+
+ h2 {
+ margin: 4px;
+ opacity: 0.7;
+ font-size: 0.8em;
+ font-weight: 400;
+ }
+
+ h3 {
+ gap: 8px;
+ display: flex;
+ font-size: 1em;
+ font-weight: 400;
+ flex-direction: row;
+ justify-content: center;
+ }
+
+ button {
+ margin: auto;
+ display: block;
+ background: rgba(0, 0, 0, 0.8);
+ }
+ }
+}
+
+.preloader {
+ height: 100%;
+ display: grid;
+ place-items: center;
+}
diff --git a/src/pages/invite/Invite.tsx b/src/pages/invite/Invite.tsx
new file mode 100644
index 00000000..cb01eaf1
--- /dev/null
+++ b/src/pages/invite/Invite.tsx
@@ -0,0 +1,87 @@
+import styles from './Invite.module.scss';
+import Button from '../../components/ui/Button';
+import { ArrowLeft } from "@styled-icons/feather";
+import Overline from '../../components/ui/Overline';
+import { Invites } from "revolt.js/dist/api/objects";
+import Preloader from '../../components/ui/Preloader';
+import { takeError } from "../../context/revoltjs/util";
+import { useHistory, useParams } from "react-router-dom";
+import ServerIcon from '../../components/common/ServerIcon';
+import UserIcon from '../../components/common/user/UserIcon';
+import { useContext, useEffect, useState } from "preact/hooks";
+import RequiresOnline from '../../context/revoltjs/RequiresOnline';
+import { AppContext, ClientStatus, StatusContext } from "../../context/revoltjs/RevoltClient";
+
+export default function Invite() {
+ const history = useHistory();
+ const client = useContext(AppContext);
+ const status = useContext(StatusContext);
+ const { code } = useParams<{ code: string }>();
+ const [ processing, setProcessing ] = useState(false);
+ const [ error, setError ] = useState(undefined);
+ const [ invite, setInvite ] = useState(undefined);
+
+ useEffect(() => {
+ if (typeof invite === 'undefined' && (status === ClientStatus.ONLINE || status === ClientStatus.READY)) {
+ client.fetchInvite(code)
+ .then(data => setInvite(data))
+ .catch(err => setError(takeError(err)))
+ }
+ }, [ status ]);
+
+ if (typeof invite === 'undefined') {
+ return (
+
+ )
+ }
+
+ return (
+
+
+
history.push('/')} />
+
+
+ { !processing &&
+
+
+
}
+
+
+ { processing ?
:
+ <>
+
{ invite.server_name }
+
#{invite.channel_name}
+
Invited by { invite.user_name }
+
+
+ >
+ }
+
+
+ );
+}