mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-26 00:50:56 -05:00
merge: branch 'master' into production
This commit is contained in:
commit
8608257066
6 changed files with 70 additions and 57 deletions
2
external/components
vendored
2
external/components
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 5e6e4a09c45baf18dcc44925f0113bad1d732e9c
|
Subproject commit 557094115d17a363eb6fb8f27c6e697e049ce623
|
2
external/lang
vendored
2
external/lang
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 8ec1e5571e3d29a93500c0199f6823d16056b6f8
|
Subproject commit 05e7213b2290dfced3d41d54cb85f49670404cf2
|
|
@ -4,12 +4,15 @@ import {
|
||||||
shift,
|
shift,
|
||||||
useFloating,
|
useFloating,
|
||||||
} from "@floating-ui/react-dom-interactions";
|
} from "@floating-ui/react-dom-interactions";
|
||||||
|
import { Plus } from "@styled-icons/boxicons-regular";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Message } from "revolt.js";
|
import { Message } from "revolt.js";
|
||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
|
|
||||||
import { createPortal } from "preact/compat";
|
import { createPortal } from "preact/compat";
|
||||||
import { useCallback, useRef } from "preact/hooks";
|
import { useCallback, useRef, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
import { IconButton } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { emojiDictionary } from "../../../../assets/emojis";
|
import { emojiDictionary } from "../../../../assets/emojis";
|
||||||
import { useClient } from "../../../../controllers/client/ClientController";
|
import { useClient } from "../../../../controllers/client/ClientController";
|
||||||
|
@ -29,6 +32,14 @@ const List = styled.div`
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-top: 0.2em;
|
margin-top: 0.2em;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.add {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .add {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,6 +90,7 @@ const Reaction = styled.div<{ active: boolean }>`
|
||||||
*/
|
*/
|
||||||
export const Reactions = observer(({ message }: Props) => {
|
export const Reactions = observer(({ message }: Props) => {
|
||||||
const client = useClient();
|
const client = useClient();
|
||||||
|
const [showPicker, setPicker] = useState(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render individual reaction entries
|
* Render individual reaction entries
|
||||||
|
@ -137,6 +149,16 @@ export const Reactions = observer(({ message }: Props) => {
|
||||||
{Array.from(optional, (id) => (
|
{Array.from(optional, (id) => (
|
||||||
<Entry key={id} id={id} user_ids={message.reactions.get(id)} />
|
<Entry key={id} id={id} user_ids={message.reactions.get(id)} />
|
||||||
))}
|
))}
|
||||||
|
{message.channel?.havePermission("React") && (
|
||||||
|
<ReactionWrapper
|
||||||
|
message={message}
|
||||||
|
open={showPicker}
|
||||||
|
setOpen={setPicker}>
|
||||||
|
<IconButton className={showPicker ? "" : "add"}>
|
||||||
|
<Plus size={20} />
|
||||||
|
</IconButton>
|
||||||
|
</ReactionWrapper>
|
||||||
|
)}
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -184,6 +184,11 @@ const Container = styled.div<{ largeEmoji: boolean }>`
|
||||||
*/
|
*/
|
||||||
const RE_QUOTE = /(^(?:>\s?){5})[>\s?]+(.*$)/gm;
|
const RE_QUOTE = /(^(?:>\s?){5})[>\s?]+(.*$)/gm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex for matching multi-line blockquotes
|
||||||
|
*/
|
||||||
|
const RE_BLOCKQUOTE = /^([^\S\r\n]*>[^\n]+\n?)+/gm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regex for matching HTML tags
|
* Regex for matching HTML tags
|
||||||
*/
|
*/
|
||||||
|
@ -214,6 +219,9 @@ function sanitise(content: string) {
|
||||||
// because remark renderer is collapsing empty
|
// because remark renderer is collapsing empty
|
||||||
// or otherwise whitespace-only lines of text
|
// or otherwise whitespace-only lines of text
|
||||||
.replace(RE_EMPTY_LINE, "")
|
.replace(RE_EMPTY_LINE, "")
|
||||||
|
|
||||||
|
// Ensure empty line after blockquotes for correct rendering
|
||||||
|
.replace(RE_BLOCKQUOTE, (match) => `${match}\n`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { Server } from "revolt.js";
|
import { Server } from "revolt.js";
|
||||||
|
|
||||||
|
import { Text } from "preact-i18n";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
|
||||||
import { Form } from "@revoltchat/ui";
|
import { Button, Column, Form, FormElement, Row } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { FileUploader } from "../../../controllers/client/jsx/legacy/FileUploads";
|
import { FileUploader } from "../../../controllers/client/jsx/legacy/FileUploads";
|
||||||
|
|
||||||
|
@ -15,7 +16,9 @@ export function EmojiUploader({ server }: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3>Upload Emoji</h3>
|
<h3>
|
||||||
|
<Text id="app.settings.server_pages.emojis.upload" />
|
||||||
|
</h3>
|
||||||
<Form
|
<Form
|
||||||
schema={{
|
schema={{
|
||||||
name: "text",
|
name: "text",
|
||||||
|
@ -42,11 +45,6 @@ export function EmojiUploader({ server }: Props) {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
submitBtn={{
|
|
||||||
children: "Save",
|
|
||||||
palette: "secondary",
|
|
||||||
disabled: !fileId,
|
|
||||||
}}
|
|
||||||
onSubmit={async ({ name }) => {
|
onSubmit={async ({ name }) => {
|
||||||
await server.client.api.put(`/custom/emoji/${fileId}`, {
|
await server.client.api.put(`/custom/emoji/${fileId}`, {
|
||||||
name,
|
name,
|
||||||
|
@ -54,8 +52,20 @@ export function EmojiUploader({ server }: Props) {
|
||||||
});
|
});
|
||||||
|
|
||||||
setFileId("");
|
setFileId("");
|
||||||
}}
|
}}>
|
||||||
/>
|
<Row>
|
||||||
|
<FormElement id="file" />
|
||||||
|
<Column>
|
||||||
|
<FormElement id="name" />
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
palette="secondary"
|
||||||
|
disabled={!fileId}>
|
||||||
|
<Text id="app.special.modals.actions.save" />
|
||||||
|
</Button>
|
||||||
|
</Column>
|
||||||
|
</Row>
|
||||||
|
</Form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,40 +8,24 @@ import { Button, Column, Row, Stacked } from "@revoltchat/ui";
|
||||||
|
|
||||||
import UserShort from "../../../components/common/user/UserShort";
|
import UserShort from "../../../components/common/user/UserShort";
|
||||||
import { EmojiUploader } from "../../../components/settings/customisation/EmojiUploader";
|
import { EmojiUploader } from "../../../components/settings/customisation/EmojiUploader";
|
||||||
import { modalController } from "../../../controllers/modals/ModalController";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
server: Server;
|
server: Server;
|
||||||
}
|
}
|
||||||
|
|
||||||
const List = styled.div`
|
const Emoji = styled(Row)`
|
||||||
gap: 8px;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Emoji = styled(Column)`
|
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
background: var(--secondary-background);
|
background: var(--secondary-background);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Preview = styled.img`
|
const Preview = styled.img`
|
||||||
width: 72px;
|
width: 32px;
|
||||||
height: 72px;
|
height: 32px;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const UserInfo = styled(Row)`
|
|
||||||
font-size: 12px;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Emojis = observer(({ server }: Props) => {
|
export const Emojis = observer(({ server }: Props) => {
|
||||||
const emoji = [...server.client.emojis.values()].filter(
|
const emoji = [...server.client.emojis.values()].filter(
|
||||||
(x) => x.parent.type === "Server" && x.parent.id === server._id,
|
(x) => x.parent.type === "Server" && x.parent.id === server._id,
|
||||||
|
@ -57,33 +41,22 @@ export const Emojis = observer(({ server }: Props) => {
|
||||||
{" – "}
|
{" – "}
|
||||||
{emoji.length}
|
{emoji.length}
|
||||||
</h3>
|
</h3>
|
||||||
<List>
|
|
||||||
{emoji.map((emoji) => (
|
{emoji.map((emoji) => (
|
||||||
<Emoji key={emoji._id} centred>
|
<Emoji key={emoji._id} centred>
|
||||||
<Stacked>
|
<Stacked>
|
||||||
<Preview src={emoji.imageURL} />
|
<Preview src={emoji.imageURL} />
|
||||||
</Stacked>
|
</Stacked>
|
||||||
<span>{`:${emoji.name}:`}</span>
|
<span>{`:${emoji.name}:`}</span>
|
||||||
<UserInfo centred>
|
<Row centred>
|
||||||
<UserShort user={emoji.creator} />
|
<UserShort user={emoji.creator} />
|
||||||
</UserInfo>
|
</Row>
|
||||||
<Button
|
|
||||||
palette="plain"
|
|
||||||
onClick={() =>
|
|
||||||
modalController.writeText(emoji._id)
|
|
||||||
}>
|
|
||||||
<Text id="app.context_menu.copy_id" />
|
|
||||||
</Button>
|
|
||||||
{server.havePermission("ManageCustomisation") && (
|
{server.havePermission("ManageCustomisation") && (
|
||||||
<Button
|
<Button palette="plain" onClick={() => emoji.delete()}>
|
||||||
palette="plain"
|
|
||||||
onClick={() => emoji.delete()}>
|
|
||||||
<Text id="app.special.modals.actions.delete" />
|
<Text id="app.special.modals.actions.delete" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Emoji>
|
</Emoji>
|
||||||
))}
|
))}
|
||||||
</List>
|
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue