mirror of
https://github.com/revoltchat/revite.git
synced 2024-12-25 23:22:06 -05:00
Add server creation button.
Add profile links / app links back. Add quoting / mentioning back.
This commit is contained in:
parent
8fe1ce3450
commit
454ee7fd6e
10 changed files with 88 additions and 83 deletions
|
@ -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 => {
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue