Add server creation button.

Add profile links / app links back.
Add quoting / mentioning back.
This commit is contained in:
Paul 2021-06-22 11:56:37 +01:00
parent 8fe1ce3450
commit 454ee7fd6e
10 changed files with 88 additions and 83 deletions

View file

@ -6,20 +6,20 @@ import IconButton from "../../ui/IconButton";
import { Send } from '@styled-icons/feather'; import { Send } from '@styled-icons/feather';
import Axios, { CancelTokenSource } from "axios"; import Axios, { CancelTokenSource } from "axios";
import { useTranslation } from "../../../lib/i18n"; import { useTranslation } from "../../../lib/i18n";
import { useCallback, useContext, useState } from "preact/hooks";
import { connectState } from "../../../redux/connector"; import { connectState } from "../../../redux/connector";
import { WithDispatcher } from "../../../redux/reducers"; import { WithDispatcher } from "../../../redux/reducers";
import { takeError } from "../../../context/revoltjs/util"; import { takeError } from "../../../context/revoltjs/util";
import TextAreaAutoSize from "../../../lib/TextAreaAutoSize"; import TextAreaAutoSize from "../../../lib/TextAreaAutoSize";
import { AppContext } from "../../../context/revoltjs/RevoltClient"; import { AppContext } from "../../../context/revoltjs/RevoltClient";
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice"; import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
import { internalEmit, internalSubscribe } from "../../../lib/eventEmitter";
import { useCallback, useContext, useEffect, useState } from "preact/hooks";
import { useIntermediate } from "../../../context/intermediate/Intermediate"; import { useIntermediate } from "../../../context/intermediate/Intermediate";
import { FileUploader, grabFiles, uploadFile } from "../../../context/revoltjs/FileUploads"; import { FileUploader, grabFiles, uploadFile } from "../../../context/revoltjs/FileUploads";
import { SingletonMessageRenderer, SMOOTH_SCROLL_ON_RECEIVE } from "../../../lib/renderer/Singleton"; import { SingletonMessageRenderer, SMOOTH_SCROLL_ON_RECEIVE } from "../../../lib/renderer/Singleton";
import FilePreview from './bars/FilePreview'; import FilePreview from './bars/FilePreview';
import { debounce } from "../../../lib/debounce"; import { debounce } from "../../../lib/debounce";
import { internalEmit } from "../../../lib/eventEmitter";
type Props = WithDispatcher & { type Props = WithDispatcher & {
channel: Channel; channel: Channel;
@ -71,6 +71,26 @@ function MessageBox({ channel, draft, dispatcher }: Props) {
} }
} }
useEffect(() => {
function append(content: string, action: 'quote' | 'mention') {
const text =
action === "quote"
? `${content
.split("\n")
.map(x => `> ${x}`)
.join("\n")}\n\n`
: `${content} `;
if (!draft || draft.length === 0) {
setMessage(text);
} else {
setMessage(`${draft}\n${text}`);
}
}
return internalSubscribe("MessageBox", "append", append);
}, [ draft ]);
async function send() { async function send() {
if (uploadState.type === 'uploading' || uploadState.type === 'sending') return; if (uploadState.type === 'uploading' || uploadState.type === 'sending') return;
@ -241,7 +261,7 @@ function MessageBox({ channel, draft, dispatcher }: Props) {
autoFocus autoFocus
hideBorder hideBorder
maxRows={5} maxRows={5}
padding={15} padding={14}
id="message" id="message"
value={draft ?? ''} value={draft ?? ''}
onKeyDown={e => { onKeyDown={e => {

View file

@ -4,6 +4,7 @@ import { generateEmoji } from "./Emoji";
import { useContext } from "preact/hooks"; import { useContext } from "preact/hooks";
import { MarkdownProps } from "./Markdown"; import { MarkdownProps } from "./Markdown";
import styles from "./Markdown.module.scss"; import styles from "./Markdown.module.scss";
import { internalEmit } from "../../lib/eventEmitter";
import { AppContext } from "../../context/revoltjs/RevoltClient"; import { AppContext } from "../../context/revoltjs/RevoltClient";
import Prism from "prismjs"; import Prism from "prismjs";
@ -70,9 +71,9 @@ if (typeof window !== "undefined") {
const pathname = url.pathname; const pathname = url.pathname;
if (pathname.startsWith("/@")) { if (pathname.startsWith("/@")) {
//InternalEventEmitter.emit("openProfile", pathname.substr(2)); internalEmit("Intermediate", "openProfile", pathname.substr(2));
} else { } else {
//InternalEventEmitter.emit("navigate", pathname); internalEmit("Intermediate", "navigate", pathname.substr(2));
} }
}; };
} }

View file

@ -7,19 +7,19 @@ export default styled.div`
user-select: none; user-select: none;
flex-direction: row; flex-direction: row;
align-items: stretch; align-items: stretch;
${ isTouchscreenDevice && css`
padding-bottom: 50px;
` }
`; `;
export const GenericSidebarBase = styled.div` export const GenericSidebarBase = styled.div<{ padding?: boolean }>`
height: 100%; height: 100%;
width: 240px; width: 240px;
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
flex-direction: column; flex-direction: column;
background: var(--secondary-background); background: var(--secondary-background);
${ props => props.padding && isTouchscreenDevice && css`
padding-bottom: 50px;
` }
`; `;
export const GenericSidebarList = styled.div` export const GenericSidebarList = styled.div`

View file

@ -49,7 +49,7 @@ function HomeSidebar(props: Props) {
channelsArr.sort((b, a) => a.timestamp.localeCompare(b.timestamp)); channelsArr.sort((b, a) => a.timestamp.localeCompare(b.timestamp));
return ( return (
<GenericSidebarBase> <GenericSidebarBase padding>
<UserHeader user={client.user!} /> <UserHeader user={client.user!} />
<ConnectionStatus /> <ConnectionStatus />
<GenericSidebarList> <GenericSidebarList>

View file

@ -1,14 +1,18 @@
import IconButton from "../../ui/IconButton";
import LineDivider from "../../ui/LineDivider"; import LineDivider from "../../ui/LineDivider";
import { mapChannelWithUnread } from "./common"; import { mapChannelWithUnread } from "./common";
import styled, { css } from "styled-components"; import styled, { css } from "styled-components";
import ServerIcon from "../../common/ServerIcon"; import ServerIcon from "../../common/ServerIcon";
import { Children } from "../../../types/Preact"; import { Children } from "../../../types/Preact";
import { PlusCircle } from "@styled-icons/feather";
import PaintCounter from "../../../lib/PaintCounter"; import PaintCounter from "../../../lib/PaintCounter";
import { attachContextMenu } from 'preact-context-menu'; import { attachContextMenu } from 'preact-context-menu';
import { connectState } from "../../../redux/connector"; import { connectState } from "../../../redux/connector";
import { Unreads } from "../../../redux/reducers/unreads"; import { Unreads } from "../../../redux/reducers/unreads";
import { Channel, Servers } from "revolt.js/dist/api/objects"; import { Channel, Servers } from "revolt.js/dist/api/objects";
import { Link, useLocation, useParams } from "react-router-dom"; import { Link, useLocation, useParams } from "react-router-dom";
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
import { useIntermediate } from "../../../context/intermediate/Intermediate";
import { useChannels, useForceUpdate, useServers } from "../../../context/revoltjs/hooks"; import { useChannels, useForceUpdate, useServers } from "../../../context/revoltjs/hooks";
import logoSVG from '../../../assets/logo.svg'; import logoSVG from '../../../assets/logo.svg';
@ -49,6 +53,10 @@ const ServersBase = styled.div`
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
${ isTouchscreenDevice && css`
padding-bottom: 50px;
` }
`; `;
const ServerList = styled.div` const ServerList = styled.div`
@ -128,7 +136,7 @@ export function ServerListSidebar({ unreads }: Props) {
const { server: server_id } = useParams<{ server?: string }>(); const { server: server_id } = useParams<{ server?: string }>();
const server = servers.find(x => x!._id == server_id); const server = servers.find(x => x!._id == server_id);
// const { openScreen } = useContext(IntermediateContext); const { openScreen } = useIntermediate();
let homeUnread: 'mention' | 'unread' | undefined; let homeUnread: 'mention' | 'unread' | undefined;
let alertCount = 0; let alertCount = 0;
@ -166,43 +174,12 @@ export function ServerListSidebar({ unreads }: Props) {
</Link> </Link>
) )
} }
<PaintCounter small />
</ServerList>
</ServersBase>
// ! FIXME: add overlay back
/*<div className={styles.servers}>
<div className={styles.list}>
<Link to={`/`}>
<div className={styles.entry}
data-active={typeof server === 'undefined' && !path.startsWith('/invite')}>
<Icon size={36} unread={homeUnread} alertCount={alertCount}>
<div className={styles.logo} />
</Icon>
</div>
</Link>
<LineDivider className={styles.divider} />
{
servers.map(entry =>
<Link to={`/server/${entry!._id}`}>
<div className={styles.entry}
data-active={entry!._id === server?._id}
onContextMenu={attachContextMenu('Menu', { server: entry!._id })}>
<Icon size={36} unread={entry.unread}>
<ServerIcon id={entry!._id} size={32} />
</Icon>
</div>
</Link>
)
}
</div>
<div className={styles.overlay}>
<div className={styles.actions}>
<IconButton onClick={() => openScreen({ id: 'special_input', type: 'create_server' })}> <IconButton onClick={() => openScreen({ id: 'special_input', type: 'create_server' })}>
<PlusCircle size={36} /> <PlusCircle size={36} />
</IconButton> </IconButton>
</div> <PaintCounter small />
</div> </ServerList>
</div> */ </ServersBase>
) )
} }

View file

@ -9,16 +9,16 @@ import Theme from "./Theme";
export default function Context({ children }: { children: Children }) { export default function Context({ children }: { children: Children }) {
return ( return (
<BrowserRouter>
<State> <State>
<Locale> <Locale>
<Intermediate> <Intermediate>
<BrowserRouter>
<ClientContext> <ClientContext>
<Theme>{children}</Theme> <Theme>{children}</Theme>
</ClientContext> </ClientContext>
</BrowserRouter>
</Intermediate> </Intermediate>
</Locale> </Locale>
</State> </State>
</BrowserRouter>
); );
} }

View file

@ -1,9 +1,11 @@
import { Attachment, Channels, EmbedImage, Servers } from "revolt.js/dist/api/objects"; import { Attachment, Channels, EmbedImage, Servers } from "revolt.js/dist/api/objects";
import { useContext, useEffect, useMemo, useState } from "preact/hooks"; import { useContext, useEffect, useMemo, useState } from "preact/hooks";
import { internalSubscribe } from "../../lib/eventEmitter";
import { Action } from "../../components/ui/Modal"; import { Action } from "../../components/ui/Modal";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { Children } from "../../types/Preact"; import { Children } from "../../types/Preact";
import { createContext } from "preact"; import { createContext } from "preact";
import { Prompt } from "react-router";
import Modals from './Modals'; import Modals from './Modals';
export type Screen = export type Screen =
@ -92,17 +94,15 @@ export default function Intermediate(props: Props) {
}, []); }, []);
useEffect(() => { useEffect(() => {
// const openProfile = (user_id: string) => const openProfile = (user_id: string) => openScreen({ id: "profile", user_id });
// openScreen({ id: "profile", user_id }); const navigate = (path: string) => history.push(path);
// const navigate = (path: string) => history.push(path);
// InternalEventEmitter.addListener("openProfile", openProfile); const subs = [
// InternalEventEmitter.addListener("navigate", navigate); internalSubscribe("Intermediate", "open_profile", openProfile),
internalSubscribe("Intermediate", "navigate", navigate)
]
return () => { return () => subs.map(unsub => unsub());
// InternalEventEmitter.removeListener("openProfile", openProfile);
// InternalEventEmitter.removeListener("navigate", navigate);
};
}, []); }, []);
return ( return (
@ -116,15 +116,19 @@ export default function Intermediate(props: Props) {
screen.id screen.id
} /** By specifying a key, we reset state whenever switching screen. */ } /** By specifying a key, we reset state whenever switching screen. */
/> />
{/*<Prompt <Prompt
when={screen.id !== 'none'} when={[ 'modify_account', 'special_prompt', 'special_input', 'image_viewer', 'profile', 'channel_info', 'user_picker' ].includes(screen.id)}
message={() => { message={(_, action) => {
if (action === 'POP') {
openScreen({ id: 'none' }); openScreen({ id: 'none' });
setTimeout(() => history.push(history.location), 0); setTimeout(() => history.push(history.location), 0);
return false; return false;
}
return true;
}} }}
/>*/} />
</IntermediateActionsContext.Provider> </IntermediateActionsContext.Provider>
</IntermediateContext.Provider> </IntermediateContext.Provider>
); );

View file

@ -138,12 +138,12 @@ function ContextMenus(props: WithDispatcher) {
case "mention": case "mention":
{ {
// edit draft internalEmit(
/*InternalEventEmitter.emit( "MessageBox",
"append_messagebox", "append",
`<@${data.user}>`, `<@${data.user}>`,
"mention" "mention"
);*/ );
} }
break; break;
@ -152,12 +152,12 @@ function ContextMenus(props: WithDispatcher) {
break; break;
case "quote_message": case "quote_message":
{ {
// edit draft internalEmit(
/*InternalEventEmitter.emit( "MessageBox",
"append_messagebox", "append",
data.content, data.content,
"quote" "quote"
);*/ );
} }
break; break;
@ -190,10 +190,10 @@ function ContextMenus(props: WithDispatcher) {
case "copy_file_link": case "copy_file_link":
{ {
const { _id, filename } = data.attachment; const { filename } = data.attachment;
writeClipboard( writeClipboard(
// ! FIXME: do from r.js // ! FIXME: do from r.js
client.generateFileURL(data.attachment) + '/${encodeURI(filename)}', client.generateFileURL(data.attachment) + `/${encodeURI(filename)}`,
); );
} }
break; break;

View file

@ -15,4 +15,7 @@ export function internalEmit(ns: string, event: string, ...args: any[]) {
/// Event List /// Event List
// - MessageRenderer/edit_last // - MessageRenderer/edit_last
// - MessageRenderer/edit_message // - MessageRenderer/edit_message
// - MessageBox/focus // - Intermediate/open_profile
// - Intermediate/navigate
// - MessageBox/append
// - TextArea/focus

View file

@ -14,7 +14,7 @@
100% {transform: scale(1.2); opacity: 0;}; 100% {transform: scale(1.2); opacity: 0;};
} }
[data-touchscreen-device="true"] .settings { .settings[data-mobile="true"] {
flex-direction: column; flex-direction: column;
background: var(--primary-header); background: var(--primary-header);
@ -45,7 +45,7 @@
} }
} }
:global(.app):not([data-touchscreen-device="true"]) .settings { .settings:not([data-mobile="true"]) {
top: 0; top: 0;
left: 0; left: 0;
z-index: 10; z-index: 10;