diff --git a/package.json b/package.json
index e2c051e9c1a13eacc31d797e500f0e156bcb2707..8862bde66511dfc2137d040ee0ba624c7af41a57 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,8 @@
     "build": "rimraf build && tsc && vite build",
     "preview": "vite preview",
     "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
-    "fmt": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'"
+    "fmt": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'",
+    "typecheck": "tsc --noEmit"
   },
   "eslintConfig": {
     "parser": "@typescript-eslint/parser",
@@ -54,6 +55,7 @@
     "markdown-it-emoji": "^2.0.0",
     "markdown-it-sub": "^1.0.0",
     "markdown-it-sup": "^1.0.0",
+    "preact-context-menu": "^0.1.5",
     "preact-i18n": "^2.4.0-preactx",
     "prettier": "^2.3.1",
     "prismjs": "^1.23.0",
diff --git a/src/components/ui/Header.tsx b/src/components/ui/Header.tsx
index 6a97dd3aeeee46c1a2f5b48c3e156117fa57e7d6..cb17b8c563e02cd8399aa475759b41d79337faaf 100644
--- a/src/components/ui/Header.tsx
+++ b/src/components/ui/Header.tsx
@@ -17,7 +17,7 @@ export default styled.div<Props>`
     flex-shrink: 0;
     align-items: center;
 
-    background-color: var(--primary-background);
+    background-color: var(--primary-header);
     background-size: cover !important;
     background-position: center !important;
 
@@ -27,6 +27,7 @@ export default styled.div<Props>`
     ` }
 
     ${ props => props.placement === 'secondary' && css`
+        background-color: var(--secondary-header);
         padding: 14px;
     ` }
 `;
diff --git a/src/components/ui/IconButton.tsx b/src/components/ui/IconButton.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..497f287cb37d000e560ba8b3109b4904e0dfc5c1
--- /dev/null
+++ b/src/components/ui/IconButton.tsx
@@ -0,0 +1,43 @@
+import styled, { css } from "styled-components";
+
+interface Props {
+    type?: 'default' | 'circle'
+}
+
+const normal = `var(--secondary-foreground)`;
+const hover = `var(--foreground)`;
+
+export default styled.div<Props>`
+    z-index: 1;
+    display: grid;
+    cursor: pointer;
+    place-items: center;
+
+    fill: ${normal};
+    color: ${normal};
+    stroke: ${normal};
+
+    a {
+        color: ${normal};
+    }
+
+    &:hover {
+        fill: ${hover};
+        color: ${hover};
+        stroke: ${hover};
+
+        a {
+            color: ${hover};
+        }
+    }
+
+    ${ props => props.type === 'circle' && css`
+        padding: 4px;
+        border-radius: 50%;
+        background-color: var(--secondary-header);
+
+        &:hover {
+            background-color: var(--primary-header);
+        }
+    ` }
+`;
diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx
index 65a93960bc65129e660bf02cced723959f7fd3b6..7d80cb81b4f5addba8304d696b806c1dd94158df 100644
--- a/src/components/ui/Modal.tsx
+++ b/src/components/ui/Modal.tsx
@@ -2,7 +2,7 @@ import Button from "./Button";
 import classNames from "classnames";
 import { Children } from "../../types/Preact";
 import { createPortal, useEffect } from "preact/compat";
-import styled, { keyframes } from "styled-components";
+import styled, { css, keyframes } from "styled-components";
 
 const open = keyframes`
     0% {opacity: 0;}
@@ -48,6 +48,26 @@ const ModalContainer = styled.div`
 `;
 
 const ModalContent = styled.div<{ [key in 'attachment' | 'noBackground' | 'border']?: boolean }>`
+    border-radius: 8px;
+    text-overflow: ellipsis;
+
+    h3 {
+        margin-top: 0;
+    }
+
+    ${ props => !props.noBackground && css`
+        padding: 1.5em;
+        background: var(--secondary-header);
+    ` }
+
+    ${ props => props.attachment && css`
+        border-radius: 8px 8px 0 0;
+    ` }
+
+    ${ props => props.border && css`
+        border-radius: 10px;
+        border: 2px solid var(--secondary-background);
+    ` }
 `;
 
 const ModalActions = styled.div`
@@ -64,7 +84,8 @@ export interface Action {
     text: Children;
     onClick: () => void;
     confirmation?: boolean;
-    style?: 'default' | 'contrast' | 'error' | 'contrast-error';
+    contrast?: boolean;
+    error?: boolean;
 }
 
 interface Props {
@@ -123,7 +144,9 @@ export default function Modal(props: Props) {
                 {props.actions && (
                     <ModalActions>
                         {props.actions.map(x => (
-                            <Button style={x.style ?? "contrast"}
+                            <Button
+                                contrast={x.contrast ?? true}
+                                error={x.error ?? false}
                                 onClick={x.onClick}
                                 disabled={props.disabled}>
                                 {x.text}
diff --git a/src/components/ui/Overline.tsx b/src/components/ui/Overline.tsx
index ee43499fad6a88a2a92a9a7afaadba261493d73e..86233697b79b414e4523da41141a4862bb749c3d 100644
--- a/src/components/ui/Overline.tsx
+++ b/src/components/ui/Overline.tsx
@@ -1,9 +1,10 @@
 import styled, { css } from "styled-components";
 import { Children } from "../../types/Preact";
+import { Text } from 'preact-i18n';
 
 interface Props {
+    error?: string;
     block?: boolean;
-    error?: Children;
     children?: Children;
     type?: "default" | "subtle" | "error";
 }
@@ -45,7 +46,9 @@ export default function Overline(props: Props) {
         <OverlineBase {...props}>
             {props.children}
             {props.children && props.error && <> &middot; </>}
-            {props.error && <Overline type="error">{props.error}</Overline>}
+            {props.error && <Overline type="error">
+                <Text id={`error.${props.error}`}>{props.error}</Text>
+            </Overline>}
         </OverlineBase>
     );
 }
diff --git a/src/context/intermediate/Intermediate.tsx b/src/context/intermediate/Intermediate.tsx
index a623d9f0be35695c58c0ed4d90e730b886273266..1c6bc8ec33f9006b5b8e97f72be159b941aca8b1 100644
--- a/src/context/intermediate/Intermediate.tsx
+++ b/src/context/intermediate/Intermediate.tsx
@@ -27,7 +27,7 @@ export type Screen =
     { type: "ban_member", target: Servers.Server, user: string }
 )) |
 ({ id: "special_input" } & (
-    { type: "create_group" | "create_server" | "set_custom_status" } |
+    { type: "create_group" | "create_server" | "set_custom_status" | "add_friend" } |
     { type: "create_channel", server: string }
 ))
 | {
diff --git a/src/context/intermediate/Modals.tsx b/src/context/intermediate/Modals.tsx
index a70c13703c9864ac898e0afd19aa597a8d61e38d..b6035595c6a8380217e7d773a03bf52884e7a0f9 100644
--- a/src/context/intermediate/Modals.tsx
+++ b/src/context/intermediate/Modals.tsx
@@ -1,12 +1,12 @@
 import { Screen } from "./Intermediate";
 
 import { ErrorModal } from "./modals/Error";
+import { InputModal } from "./modals/Input";
+import { PromptModal } from "./modals/Prompt";
 import { SignedOutModal } from "./modals/SignedOut";
 import { ClipboardModal } from "./modals/Clipboard";
 import { OnboardingModal } from "./modals/Onboarding";
 import { ModifyAccountModal } from "./modals/ModifyAccount";
-import { InputModal, SpecialInputModal } from "./modals/Input";
-import { PromptModal, SpecialPromptModal } from "./modals/Prompt";
 
 export interface Props {
     screen: Screen;
@@ -19,12 +19,8 @@ export default function Modals({ screen, openScreen }: Props) {
     switch (screen.id) {
         case "_prompt":
             return <PromptModal onClose={onClose} {...screen} />;
-        case "special_prompt":
-            return <SpecialPromptModal onClose={onClose} {...screen} />;
         case "_input":
             return <InputModal onClose={onClose} {...screen} />;
-        case "special_input":
-            return <SpecialInputModal onClose={onClose} {...screen} />;
         case "error":
             return <ErrorModal onClose={onClose} {...screen} />;
         case "signed_out":
diff --git a/src/context/intermediate/Popovers.tsx b/src/context/intermediate/Popovers.tsx
index 565d762b2b7b6df26b8a164efcb702f065ef6a14..f91b02dcee6a073c1bc58cf9c66983a050b11735 100644
--- a/src/context/intermediate/Popovers.tsx
+++ b/src/context/intermediate/Popovers.tsx
@@ -2,6 +2,8 @@ import { IntermediateContext, useIntermediate } from "./Intermediate";
 import { useContext } from "preact/hooks";
 
 import { UserPicker } from "./popovers/UserPicker";
+import { SpecialInputModal } from "./modals/Input";
+import { SpecialPromptModal } from "./modals/Prompt";
 import { UserProfile } from "./popovers/UserProfile";
 import { ImageViewer } from "./popovers/ImageViewer";
 import { ChannelInfo } from "./popovers/ChannelInfo";
@@ -21,6 +23,10 @@ export default function Popovers() {
             return <ImageViewer {...screen} onClose={onClose} />;
         case "channel_info":
             return <ChannelInfo {...screen} onClose={onClose} />;
+        case "special_prompt":
+            return <SpecialPromptModal onClose={onClose} {...screen} />;
+        case "special_input":
+            return <SpecialInputModal onClose={onClose} {...screen} />;
     }
 
     return null;
diff --git a/src/context/intermediate/modals/Input.tsx b/src/context/intermediate/modals/Input.tsx
index 4aa68f9b960d9eaafdc31b85af69b360a594d49f..3d2878522e04e1d4bcc13096baa03e3b8f7f18b8 100644
--- a/src/context/intermediate/modals/Input.tsx
+++ b/src/context/intermediate/modals/Input.tsx
@@ -12,7 +12,7 @@ import { AppContext } from "../../revoltjs/RevoltClient";
 interface Props {
     onClose: () => void;
     question: Children;
-    field: Children;
+    field?: Children;
     defaultValue?: string;
     callback: (value: string) => Promise<void>;
 }
@@ -53,9 +53,9 @@ export function InputModal({
             ]}
             onClose={onClose}
         >
-            <Overline error={error} block>
+            { field ? <Overline error={error} block>
                 {field}
-            </Overline>
+            </Overline> : (error && <Overline error={error} type="error" block />) }
             <InputBox
                 value={value}
                 onChange={e => setValue(e.currentTarget.value)}
@@ -65,7 +65,7 @@ export function InputModal({
 }
 
 type SpecialProps = { onClose: () => void } & (
-    { type: "create_group" | "create_server" | "set_custom_status" } |
+    { type: "create_group" | "create_server" | "set_custom_status" | "add_friend" } |
     { type: "create_channel", server: string }
 )
 
@@ -144,6 +144,15 @@ export function SpecialInputModal(props: SpecialProps) {
                 }
             />;
         }
+        case "add_friend": {
+            return <InputModal
+                onClose={onClose}
+                question={"Add Friend"}
+                callback={username =>
+                    client.users.addFriend(username)
+                }
+            />;
+        }
         default: return null;
     }
 }
diff --git a/src/context/intermediate/modals/Prompt.tsx b/src/context/intermediate/modals/Prompt.tsx
index c5aedfa9c113a078db32e2648b2d9e6322954f71..645d395e30ca494cc5d9792932c765d5b50120f4 100644
--- a/src/context/intermediate/modals/Prompt.tsx
+++ b/src/context/intermediate/modals/Prompt.tsx
@@ -1,7 +1,7 @@
 import { Text } from "preact-i18n";
 import styles from './Prompt.module.scss';
 import { Children } from "../../../types/Preact";
-import { IntermediateContext, useIntermediate } from "../Intermediate";
+import { useIntermediate } from "../Intermediate";
 import InputBox from "../../../components/ui/InputBox";
 import Overline from "../../../components/ui/Overline";
 import UserIcon from "../../../components/common/UserIcon";
@@ -82,7 +82,8 @@ export function SpecialPromptModal(props: SpecialProps) {
                     actions={[
                         {
                             confirmation: true,
-                            style: 'contrast-error',
+                            contrast: true,
+                            error: true,
                             text: <Text id="app.special.modals.actions.delete" />,
                             onClick: async () => {
                                 setProcessing(true);
@@ -162,7 +163,8 @@ export function SpecialPromptModal(props: SpecialProps) {
                     actions={[
                         {
                             text: <Text id="app.special.modals.actions.kick" />,
-                            style: 'contrast-error',
+                            contrast: true,
+                            error: true,
                             confirmation: true,
                             onClick: async () => {
                                 setProcessing(true);
@@ -200,7 +202,8 @@ export function SpecialPromptModal(props: SpecialProps) {
                     actions={[
                         {
                             text: <Text id="app.special.modals.actions.ban" />,
-                            style: 'contrast-error',
+                            contrast: true,
+                            error: true,
                             confirmation: true,
                             onClick: async () => {
                                 setProcessing(true);
diff --git a/src/lib/stopPropagation.ts b/src/lib/stopPropagation.ts
new file mode 100644
index 0000000000000000000000000000000000000000..98c9fa60450edf28b6846036eb981c17860dc03c
--- /dev/null
+++ b/src/lib/stopPropagation.ts
@@ -0,0 +1,4 @@
+export const stopPropagation = (ev: JSX.TargetedMouseEvent<HTMLDivElement>, _consume?: any) => {
+    ev.preventDefault();
+    ev.stopPropagation();
+};
diff --git a/src/pages/App.tsx b/src/pages/App.tsx
index ebe37fe558257d96740abc928bd4f3caf82e4e57..4648649f8738c73e52010ac8101c1258964b7eed 100644
--- a/src/pages/App.tsx
+++ b/src/pages/App.tsx
@@ -1,12 +1,22 @@
 import { Docked, OverlappingPanels } from "react-overlapping-panels";
 import { isTouchscreenDevice } from "../lib/isTouchscreenDevice";
+import Popovers from "../context/intermediate/Popovers";
 import { Switch, Route } from "react-router-dom";
+import styled from "styled-components";
 
 import LeftSidebar from "../components/navigation/LeftSidebar";
 import RightSidebar from "../components/navigation/RightSidebar";
 
 import Home from './home/Home';
-import Popovers from "../context/intermediate/Popovers";
+import Friends from "./friends/Friends";
+
+const Routes = styled.div`
+    min-width: 0;
+    display: flex;
+    overflow: hidden;
+    flex-direction: column;
+    background: var(--primary-background);
+`;
 
 export default function App() {
     return (
@@ -16,12 +26,76 @@ export default function App() {
             leftPanel={{ width: 292, component: <LeftSidebar /> }}
             rightPanel={{ width: 240, component: <RightSidebar /> }}
             docked={isTouchscreenDevice ? Docked.None : Docked.Left}>
-            <Switch>
-                <Route path="/">
-                    <Home />
-                </Route>
-            </Switch>
+            <Routes>
+                <Switch>
+                    <Route path="/friends">
+                        <Friends />
+                    </Route>
+
+                    <Route path="/">
+                        <Home />
+                    </Route>
+                </Switch>
+            </Routes>
             <Popovers />
         </OverlappingPanels>
     );
 };
+
+/**
+ * 
+ * <Route path="/channel/:channel/message/:message">
+                            <ChannelWrapper />
+                        </Route> 
+                        <Route path="/server/:server/channel/:channel/settings/:page">
+                            <ChannelSettings key="channel_settings" />
+                        </Route>
+                        <Route path="/server/:server/channel/:channel/settings">
+                            <ChannelSettings key="channel_settings" />
+                        </Route>
+                        <Route path="/server/:server/settings/:page">
+                            <ServerSettings key="channel_settings" />
+                        </Route>
+                        <Route path="/server/:server/settings">
+                            <ServerSettings key="channel_settings" />
+                        </Route>
+                        <Route path="/channel/:channel/settings/:page">
+                            <ChannelSettings key="channel_settings" />
+                        </Route>
+                        <Route path="/channel/:channel/settings">
+                            <ChannelSettings key="channel_settings" />
+                        </Route>
+
+                        <Route path="/settings/:page">
+                            <Settings key="settings" />
+                        </Route>
+                        <Route path="/settings">
+                            <Settings key="settings" />
+                        </Route>
+
+                        <Route path="/server/:server/channel/:channel">
+                            <ChannelWrapper />
+                        </Route>
+                        <Route path="/server/:server" />
+                        <Route path="/channel/:channel">
+                            <ChannelWrapper />
+                        </Route>
+                        
+                        <Route path="/friends">
+                            <Friends />
+                        </Route>
+                        <Route path="/dev">
+                            <Developer />
+                        </Route>
+                        
+                        <Route path="/open/:id">
+                            <Open />
+                        </Route>
+                        {/*<Route path="/invite/:code">
+                            <OpenInvite />
+                        </Route>
+
+                        <Route path="/">
+                            <Home />
+                        </Route>
+ */
diff --git a/src/pages/friends/Friend.module.scss b/src/pages/friends/Friend.module.scss
new file mode 100644
index 0000000000000000000000000000000000000000..b9e90c0091b5650e4b221a3a3acc64f4d1e00d61
--- /dev/null
+++ b/src/pages/friends/Friend.module.scss
@@ -0,0 +1,71 @@
+.list {
+    padding: 16px;
+    user-select: none;
+    overflow-y: scroll;
+
+    &[data-empty="true"] {
+        img {
+            height: 120px;
+            border-radius: 8px;
+        }
+
+        gap: 16px;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        flex-direction: column;
+        justify-content: center;
+    }
+}
+
+.friend {
+    padding: 10px;
+    display: flex;
+    border-radius: 5px;
+    align-items: center;
+    flex-direction: row;
+    cursor: pointer;
+
+    &:hover {
+        background: var(--secondary-background);
+
+        :global(.button) {
+            background-color: var(--primary-background);
+        }
+    }
+
+    .name {
+        flex-grow: 1;
+        margin: 0 12px;
+        font-size: 16px;
+
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+
+        .subtext {
+            font-size: 12px;
+            color: var(--tertiary-foreground);
+        }
+    }
+
+    .actions {
+        display: flex;
+        gap: 12px;
+
+        > div {
+            height: 32px;
+            width: 32px;
+        }
+    }
+}
+
+//! FIXME: Move this to the Header component, do this:
+// 1. Check if header has topic, if yes, flex-grow: 0 on the title.
+// 2. If header has no topic (example: friends page), flex-grow 1 on the header title.
+.title {
+    flex-grow: 1;
+}
diff --git a/src/pages/friends/Friend.tsx b/src/pages/friends/Friend.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..d27ee852560c97f79136baa5e18458507604cd6c
--- /dev/null
+++ b/src/pages/friends/Friend.tsx
@@ -0,0 +1,90 @@
+import { Text } from "preact-i18n";
+import { Link } from "react-router-dom";
+import styles from "./Friend.module.scss";
+import { useContext } from "preact/hooks";
+import { Children } from "../../types/Preact";
+import { X, Plus, Mail } from "@styled-icons/feather";
+import UserIcon from "../../components/common/UserIcon";
+import IconButton from "../../components/ui/IconButton";
+import { attachContextMenu } from "preact-context-menu";
+import { User, Users } from "revolt.js/dist/api/objects";
+import UserStatus from '../../components/common/UserStatus';
+import { stopPropagation } from "../../lib/stopPropagation";
+import { AppContext } from "../../context/revoltjs/RevoltClient";
+import { useIntermediate } from "../../context/intermediate/Intermediate";
+
+interface Props {
+    user: User;
+}
+
+export function Friend({ user }: Props) {
+    const client = useContext(AppContext);
+    const { openScreen } = useIntermediate();
+
+    const actions: Children[] = [];
+    let subtext: Children = null;
+
+    if (user.relationship === Users.Relationship.Friend) {
+        subtext = <UserStatus user={user} />
+        actions.push(
+            <IconButton type="circle"
+                onClick={stopPropagation}>
+                <Link to={'/open/' + user._id}>
+                    <Mail size={20} />
+                </Link>
+            </IconButton>
+        );
+    }
+
+    if (user.relationship === Users.Relationship.Incoming) {
+        actions.push(
+            <IconButton type="circle"
+                onClick={ev => stopPropagation(ev, client.users.addFriend(user.username))}>
+                <Plus size={24} />
+            </IconButton>
+        );
+
+        subtext = <Text id="app.special.friends.incoming" />;
+    }
+
+    if (user.relationship === Users.Relationship.Outgoing) {
+        subtext = <Text id="app.special.friends.outgoing" />;
+    }
+
+    if (
+        user.relationship === Users.Relationship.Friend ||
+        user.relationship === Users.Relationship.Outgoing ||
+        user.relationship === Users.Relationship.Incoming
+    ) {
+        actions.push(
+            <IconButton type="circle"
+                onClick={ev => stopPropagation(ev, client.users.removeFriend(user._id))}>
+                <X size={24} />
+            </IconButton>
+        );
+    }
+
+    if (user.relationship === Users.Relationship.Blocked) {
+        actions.push(
+            <IconButton type="circle"
+                onClick={ev => stopPropagation(ev, client.users.unblockUser(user._id))}>
+                <X size={24} />
+            </IconButton>
+        );
+    }
+
+    return (
+        <div className={styles.friend}
+            onClick={() => openScreen({ id: 'profile', user_id: user._id })}
+            onContextMenu={attachContextMenu('Menu', { user: user._id })}>
+            <UserIcon target={user} size={32} status />
+            <div className={styles.name}>
+                <span>@{user.username}</span>
+                {subtext && (
+                    <span className={styles.subtext}>{subtext}</span>
+                )}
+            </div>
+            <div className={styles.actions}>{actions}</div>
+        </div>
+    );
+}
diff --git a/src/pages/friends/Friends.tsx b/src/pages/friends/Friends.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..9460f8e4619b42dc24f4fbc1857bde49e68a493e
--- /dev/null
+++ b/src/pages/friends/Friends.tsx
@@ -0,0 +1,85 @@
+import styles from "./Friend.module.scss";
+import { UserPlus } from "@styled-icons/feather";
+
+import { Friend } from "./Friend";
+import { Text } from "preact-i18n";
+import Header from "../../components/ui/Header";
+import Overline from "../../components/ui/Overline";
+import IconButton from "../../components/ui/IconButton";
+import { useUsers } from "../../context/revoltjs/hooks";
+import { User, Users } from "revolt.js/dist/api/objects";
+import { useIntermediate } from "../../context/intermediate/Intermediate";
+
+export default function Friends() {
+    const { openScreen } = useIntermediate();
+
+    const users = useUsers() as User[];
+    users.sort((a, b) => a.username.localeCompare(b.username));
+
+    const pending = users.filter(
+        x =>
+            x.relationship === Users.Relationship.Incoming ||
+            x.relationship === Users.Relationship.Outgoing
+    );
+    const friends = users.filter(
+        x => x.relationship === Users.Relationship.Friend
+    );
+    const blocked = users.filter(
+        x => x.relationship === Users.Relationship.Blocked
+    );
+
+    return (
+        <>
+            <Header placement="primary">
+                <div className={styles.title}>
+                    <Text id="app.navigation.tabs.friends" />
+                </div>
+                <div className="actions">
+                    <IconButton onClick={() => openScreen({ id: 'special_input', type: 'add_friend' })}>
+                        <UserPlus size={24} />
+                    </IconButton>
+                </div>
+            </Header>
+            <div
+                className={styles.list}
+                data-empty={
+                    pending.length + friends.length + blocked.length === 0
+                }
+            >
+                {pending.length + friends.length + blocked.length === 0 && (
+                    <>
+                        <img src="https://img.insrt.uk/xexu7/XOPoBUTI47.png/raw" />
+                        <Text id="app.special.friends.nobody" />
+                    </>
+                )}
+                {pending.length > 0 && (
+                    <Overline type="subtle">
+                        <Text id="app.special.friends.pending" /> –{" "}
+                        {pending.length}
+                    </Overline>
+                )}
+                {pending.map(y => (
+                    <Friend key={y._id} user={y} />
+                ))}
+                {friends.length > 0 && (
+                    <Overline type="subtle">
+                        <Text id="app.navigation.tabs.friends" /> –{" "}
+                        {friends.length}
+                    </Overline>
+                )}
+                {friends.map(y => (
+                    <Friend key={y._id} user={y} />
+                ))}
+                {blocked.length > 0 && (
+                    <Overline type="subtle">
+                        <Text id="app.special.friends.blocked" /> –{" "}
+                        {blocked.length}
+                    </Overline>
+                )}
+                {blocked.map(y => (
+                    <Friend key={y._id} user={y} />
+                ))}
+            </div>
+        </>
+    );
+}
diff --git a/src/styles/_elements.scss b/src/styles/_elements.scss
index d0e652411d01e81e1cb099267e89a5afdf677dbd..f019eff332e59e959c63136d2ccb4133d7a17cda 100644
--- a/src/styles/_elements.scss
+++ b/src/styles/_elements.scss
@@ -1,3 +1,8 @@
+:disabled {
+    opacity: 0.5;
+    pointer-events: none;
+}
+
 ::-webkit-scrollbar {
     width: 3px;
     height: 3px;
diff --git a/src/types/Preact.ts b/src/types/Preact.ts
index 80ac4895ea495941fd9d076d4c9c6fb5aac13fb1..dbbea16e674bee4ccced7e757685e020d8ffb6d0 100644
--- a/src/types/Preact.ts
+++ b/src/types/Preact.ts
@@ -1,4 +1,4 @@
 import { VNode } from "preact";
 
-export type Child = VNode | string | false | undefined;
+export type Child = VNode | string | number | boolean | undefined | null;
 export type Children = Child | Child[] | Children[];
diff --git a/yarn.lock b/yarn.lock
index 16f513a7788d5a8922ed7d1f46969fb2a198a561..effb671864e9d8a26b967918ea0d5cd5849ec2ab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3038,6 +3038,13 @@ postcss@^8.3.0:
     nanoid "^3.1.23"
     source-map-js "^0.6.2"
 
+preact-context-menu@^0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/preact-context-menu/-/preact-context-menu-0.1.5.tgz#51d13b0eceed8bd53493f2bdbce36e7c74ff8575"
+  integrity sha512-cQxcOf4w8MZAQtLpQeX80TQ2TzSKD/z6rnV+654xiHzqQp2pSV+qE0IEZLkUNz88ZmtpIy6GnB/6pCnCGjS4Ww==
+  dependencies:
+    preact "^10.4.6"
+
 preact-i18n@^2.4.0-preactx:
   version "2.4.0-preactx"
   resolved "https://registry.yarnpkg.com/preact-i18n/-/preact-i18n-2.4.0-preactx.tgz#fbcb2e3ae22744c7fef5a102db2ef7506057d082"
@@ -3051,7 +3058,7 @@ preact-markup@^2.0.0:
   resolved "https://registry.yarnpkg.com/preact-markup/-/preact-markup-2.1.1.tgz#0451e7eed1dac732d7194c34a7f16ff45a2cfdd7"
   integrity sha512-8JL2p36mzK8XkspOyhBxUSPjYwMxDM0L5BWBZWxsZMVW8WsGQrYQDgVuDKkRspt2hwrle+Cxr/053hpc9BJwfw==
 
-preact@^10.0.0, preact@^10.5.13:
+preact@^10.0.0, preact@^10.4.6, preact@^10.5.13:
   version "10.5.13"
   resolved "https://registry.yarnpkg.com/preact/-/preact-10.5.13.tgz#85f6c9197ecd736ce8e3bec044d08fd1330fa019"
   integrity sha512-q/vlKIGNwzTLu+jCcvywgGrt+H/1P/oIRSD6mV4ln3hmlC+Aa34C7yfPI4+5bzW8pONyVXYS7SvXosy2dKKtWQ==