mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-29 02:10:59 -05:00
merge: branch 'master' into production
This commit is contained in:
commit
df20ab7407
36 changed files with 369 additions and 192 deletions
2
external/components
vendored
2
external/components
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit ab0fc1af739f877c8f416dcd7e47d25aacbb7eea
|
Subproject commit e79862b5972b57c016b4c08676ac1b90bd52ee83
|
2
external/lang
vendored
2
external/lang
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 843cece2854185651e17765bcb78109d22eba769
|
Subproject commit f95ec6dc8200adba7925425d4cf2ae0c16f049c3
|
|
@ -73,7 +73,7 @@
|
||||||
"@fontsource/space-mono": "^4.4.5",
|
"@fontsource/space-mono": "^4.4.5",
|
||||||
"@fontsource/ubuntu": "^4.4.5",
|
"@fontsource/ubuntu": "^4.4.5",
|
||||||
"@fontsource/ubuntu-mono": "^4.4.5",
|
"@fontsource/ubuntu-mono": "^4.4.5",
|
||||||
"@hcaptcha/react-hcaptcha": "^0.3.6",
|
"@hcaptcha/react-hcaptcha": "^1.4.4",
|
||||||
"@insertish/vite-plugin-babel-macros": "^1.0.5",
|
"@insertish/vite-plugin-babel-macros": "^1.0.5",
|
||||||
"@preact/preset-vite": "^2.0.0",
|
"@preact/preset-vite": "^2.0.0",
|
||||||
"@revoltchat/ui": "^1.0.77",
|
"@revoltchat/ui": "^1.0.77",
|
||||||
|
@ -81,7 +81,7 @@
|
||||||
"@styled-icons/boxicons-logos": "^10.38.0",
|
"@styled-icons/boxicons-logos": "^10.38.0",
|
||||||
"@styled-icons/boxicons-regular": "^10.38.0",
|
"@styled-icons/boxicons-regular": "^10.38.0",
|
||||||
"@styled-icons/boxicons-solid": "^10.38.0",
|
"@styled-icons/boxicons-solid": "^10.38.0",
|
||||||
"@styled-icons/simple-icons": "^10.33.0",
|
"@styled-icons/simple-icons": "^10.45.0",
|
||||||
"@tippyjs/react": "4.2.6",
|
"@tippyjs/react": "4.2.6",
|
||||||
"@traptitech/markdown-it-katex": "^3.4.3",
|
"@traptitech/markdown-it-katex": "^3.4.3",
|
||||||
"@traptitech/markdown-it-spoiler": "^1.1.6",
|
"@traptitech/markdown-it-spoiler": "^1.1.6",
|
||||||
|
@ -89,9 +89,9 @@
|
||||||
"@types/lodash": "^4",
|
"@types/lodash": "^4",
|
||||||
"@types/lodash.defaultsdeep": "^4.6.6",
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
||||||
"@types/lodash.isequal": "^4.5.5",
|
"@types/lodash.isequal": "^4.5.5",
|
||||||
"@types/node": "^15.12.4",
|
"@types/node": "^15.14.9",
|
||||||
"@types/preact-i18n": "^2.3.0",
|
"@types/preact-i18n": "^2.3.0",
|
||||||
"@types/prismjs": "^1.16.5",
|
"@types/prismjs": "^1.26.0",
|
||||||
"@types/react-beautiful-dnd": "^13",
|
"@types/react-beautiful-dnd": "^13",
|
||||||
"@types/react-helmet": "^6.1.1",
|
"@types/react-helmet": "^6.1.1",
|
||||||
"@types/react-router-dom": "^5.1.7",
|
"@types/react-router-dom": "^5.1.7",
|
||||||
|
|
1
packages/components
Submodule
1
packages/components
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit d314b2d191124f1b487ebd72409e748c1bfccb87
|
1
packages/hast-util-table-cell-style
Submodule
1
packages/hast-util-table-cell-style
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7803fa54410a7ef9fc3149c482253e74ca1d7d71
|
1
packages/revolt.js
Submodule
1
packages/revolt.js
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 39d1f596e280a28278d913e1e60e4d5298d71578
|
|
@ -14,12 +14,21 @@ import {
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Message, API } from "revolt.js";
|
import { Message, API } from "revolt.js";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
|
import { decodeTime } from "ulid";
|
||||||
|
|
||||||
import { useTriggerEvents } from "preact-context-menu";
|
import { useTriggerEvents } from "preact-context-menu";
|
||||||
|
import { Text } from "preact-i18n";
|
||||||
|
|
||||||
|
import { Row } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { TextReact } from "../../../lib/i18n";
|
import { TextReact } from "../../../lib/i18n";
|
||||||
|
|
||||||
|
import { useApplicationState } from "../../../mobx/State";
|
||||||
|
|
||||||
|
import { dayjs } from "../../../context/Locale";
|
||||||
|
|
||||||
import Markdown from "../../markdown/Markdown";
|
import Markdown from "../../markdown/Markdown";
|
||||||
|
import Tooltip from "../Tooltip";
|
||||||
import UserShort from "../user/UserShort";
|
import UserShort from "../user/UserShort";
|
||||||
import MessageBase, { MessageDetail, MessageInfo } from "./MessageBase";
|
import MessageBase, { MessageDetail, MessageInfo } from "./MessageBase";
|
||||||
|
|
||||||
|
@ -78,6 +87,8 @@ export const SystemMessage = observer(
|
||||||
const data = message.asSystemMessage;
|
const data = message.asSystemMessage;
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
|
|
||||||
|
const settings = useApplicationState().settings;
|
||||||
|
|
||||||
const SystemMessageIcon =
|
const SystemMessageIcon =
|
||||||
iconDictionary[data.type as API.SystemMessage["type"]] ??
|
iconDictionary[data.type as API.SystemMessage["type"]] ??
|
||||||
InfoCircle;
|
InfoCircle;
|
||||||
|
@ -103,16 +114,39 @@ export const SystemMessage = observer(
|
||||||
case "user_joined":
|
case "user_joined":
|
||||||
case "user_left":
|
case "user_left":
|
||||||
case "user_kicked":
|
case "user_kicked":
|
||||||
case "user_banned":
|
case "user_banned": {
|
||||||
|
const createdAt = data.user ? decodeTime(data.user._id) : null;
|
||||||
children = (
|
children = (
|
||||||
|
<Row centred>
|
||||||
<TextReact
|
<TextReact
|
||||||
id={`app.main.channel.system.${data.type}`}
|
id={`app.main.channel.system.${data.type}`}
|
||||||
fields={{
|
fields={{
|
||||||
user: <UserShort user={data.user} />,
|
user: <UserShort user={data.user} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{data.type == "user_joined" &&
|
||||||
|
createdAt &&
|
||||||
|
(settings.get("appearance:show_account_age") ||
|
||||||
|
Date.now() - createdAt <
|
||||||
|
1000 * 60 * 60 * 24 * 7) && (
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
<Text
|
||||||
|
id="app.main.channel.system.registered_at"
|
||||||
|
fields={{
|
||||||
|
time: dayjs(
|
||||||
|
createdAt,
|
||||||
|
).fromNow(),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}>
|
||||||
|
<InfoCircle size={16} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case "channel_renamed":
|
case "channel_renamed":
|
||||||
children = (
|
children = (
|
||||||
<TextReact
|
<TextReact
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Channel } from "revolt.js";
|
import { Channel, Member } from "revolt.js";
|
||||||
import styled from "styled-components/macro";
|
import styled from "styled-components/macro";
|
||||||
|
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
@ -60,6 +60,8 @@ const Base = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default observer(({ channel }: Props) => {
|
export default observer(({ channel }: Props) => {
|
||||||
|
const client = channel.client;
|
||||||
|
|
||||||
const users = channel.typing.filter(
|
const users = channel.typing.filter(
|
||||||
(x) =>
|
(x) =>
|
||||||
typeof x !== "undefined" &&
|
typeof x !== "undefined" &&
|
||||||
|
@ -67,24 +69,47 @@ export default observer(({ channel }: Props) => {
|
||||||
x.relationship !== "Blocked",
|
x.relationship !== "Blocked",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (users.length > 0) {
|
const members = users.map((user) => {
|
||||||
users.sort((a, b) =>
|
return client.members.getKey({
|
||||||
a!._id.toUpperCase().localeCompare(b!._id.toUpperCase()),
|
server: channel.server_id!,
|
||||||
|
user: user!._id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const getName = (member: Member) => {
|
||||||
|
return member.nickname === null
|
||||||
|
? member.user?.username
|
||||||
|
: member.nickname;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAvatar = (member: Member) => {
|
||||||
|
const memberAvatarURL = member.generateAvatarURL({
|
||||||
|
max_side: 256,
|
||||||
|
});
|
||||||
|
|
||||||
|
return memberAvatarURL === undefined
|
||||||
|
? member.user?.generateAvatarURL({ max_side: 256 })
|
||||||
|
: memberAvatarURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (members.length > 0) {
|
||||||
|
members.sort((a, b) =>
|
||||||
|
a!._id.user.toUpperCase().localeCompare(b!._id.user.toUpperCase()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let text;
|
let text;
|
||||||
if (users.length >= 5) {
|
if (members.length >= 5) {
|
||||||
text = <Text id="app.main.channel.typing.several" />;
|
text = <Text id="app.main.channel.typing.several" />;
|
||||||
} else if (users.length > 1) {
|
} else if (members.length > 1) {
|
||||||
const userlist = [...users].map((x) => x!.username);
|
const memberlist = [...members].map((x) => getName(x!));
|
||||||
const user = userlist.pop();
|
const member = memberlist.pop();
|
||||||
|
|
||||||
text = (
|
text = (
|
||||||
<Text
|
<Text
|
||||||
id="app.main.channel.typing.multiple"
|
id="app.main.channel.typing.multiple"
|
||||||
fields={{
|
fields={{
|
||||||
user,
|
user: member,
|
||||||
userlist: userlist.join(", "),
|
userlist: memberlist.join(", "),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -92,7 +117,7 @@ export default observer(({ channel }: Props) => {
|
||||||
text = (
|
text = (
|
||||||
<Text
|
<Text
|
||||||
id="app.main.channel.typing.single"
|
id="app.main.channel.typing.single"
|
||||||
fields={{ user: users[0]!.username }}
|
fields={{ user: getName(members[0]!) }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -101,11 +126,11 @@ export default observer(({ channel }: Props) => {
|
||||||
<Base>
|
<Base>
|
||||||
<div>
|
<div>
|
||||||
<div className="avatars">
|
<div className="avatars">
|
||||||
{users.map((user) => (
|
{members.map((member) => (
|
||||||
<img
|
<img
|
||||||
key={user!._id}
|
key={member!._id.user}
|
||||||
loading="eager"
|
loading="eager"
|
||||||
src={user!.generateAvatarURL({ max_side: 256 })}
|
src={getAvatar(member!)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default function EmbedMedia({ embed, width, height }: Props) {
|
||||||
case "Lightspeed":
|
case "Lightspeed":
|
||||||
return (
|
return (
|
||||||
<iframe
|
<iframe
|
||||||
src={`https://next.lightspeed.tv/embed/${embed.special.id}`}
|
src={`https://new.lightspeed.tv/embed/${embed.special.id}/stream`}
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
allowFullScreen
|
allowFullScreen
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
|
|
|
@ -20,6 +20,7 @@ const Base = styled.pre`
|
||||||
* Copy codeblock contents button styles
|
* Copy codeblock contents button styles
|
||||||
*/
|
*/
|
||||||
const Lang = styled.div`
|
const Lang = styled.div`
|
||||||
|
font-family: var(--monospace-font);
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
|
|
||||||
|
|
|
@ -118,20 +118,20 @@ export default function MemberList({
|
||||||
return (
|
return (
|
||||||
<NoOomfie>
|
<NoOomfie>
|
||||||
<div>
|
<div>
|
||||||
Offline users temporarily disabled for this
|
Offline users have temporarily been disabled for
|
||||||
server, see issue{" "}
|
larger servers - see{" "}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/revoltchat/delta/issues/128"
|
href="https://github.com/revoltchat/backend/issues/178"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer">
|
rel="noreferrer">
|
||||||
#128
|
issue #178
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
for when this will be resolved.
|
for when this will be resolved.
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
You may re-enable them in{" "}
|
You may re-enable them{" "}
|
||||||
<Link to="/settings/experiments">
|
<Link to="/settings/experiments">
|
||||||
<a>experiments</a>
|
<a>here</a>
|
||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,6 +26,20 @@ export default function AppearanceOptions() {
|
||||||
<Text id="app.settings.pages.appearance.appearance_options.show_send_desc" />
|
<Text id="app.settings.pages.appearance.appearance_options.show_send_desc" />
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{/* Option to always show the account creation age next to join system messages. */}
|
||||||
|
<ObservedInputElement
|
||||||
|
type="checkbox"
|
||||||
|
value={() =>
|
||||||
|
settings.get("appearance:show_account_age") ?? false
|
||||||
|
}
|
||||||
|
onChange={(v) => settings.set("appearance:show_account_age", v)}
|
||||||
|
title={
|
||||||
|
<Text id="app.settings.pages.appearance.appearance_options.show_account_age" />
|
||||||
|
}
|
||||||
|
description={
|
||||||
|
<Text id="app.settings.pages.appearance.appearance_options.show_account_age_desc" />
|
||||||
|
}
|
||||||
|
/>
|
||||||
<hr />
|
<hr />
|
||||||
<h3>
|
<h3>
|
||||||
<Text id="app.settings.pages.appearance.theme_options.title" />
|
<Text id="app.settings.pages.appearance.theme_options.title" />
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { noopAsync } from "../../../lib/js";
|
||||||
import { takeError } from "../../client/jsx/error";
|
import { takeError } from "../../client/jsx/error";
|
||||||
import { modalController } from "../ModalController";
|
import { modalController } from "../ModalController";
|
||||||
import { ModalProps } from "../types";
|
import { ModalProps } from "../types";
|
||||||
|
import { IS_REVOLT } from "../../../version";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Code block which displays invite
|
* Code block which displays invite
|
||||||
|
@ -78,7 +79,7 @@ export default function CreateInvite({
|
||||||
children: <Text id="app.context_menu.copy_link" />,
|
children: <Text id="app.context_menu.copy_link" />,
|
||||||
onClick: () =>
|
onClick: () =>
|
||||||
modalController.writeText(
|
modalController.writeText(
|
||||||
`${window.location.protocol}//${window.location.host}/invite/${code}`,
|
IS_REVOLT ? `https://rvlt.gg/${code}` : `${window.location.host}/invite/${code}`
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -12,34 +12,19 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
div {
|
div {
|
||||||
flex: 1;
|
&.container {
|
||||||
|
max-width: 750px;
|
||||||
|
flex-grow: 1;
|
||||||
|
align-items: left;
|
||||||
|
}
|
||||||
|
|
||||||
&.header {
|
&.header {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 3em;
|
padding-top: 5em;
|
||||||
display: flex;
|
display: flex;
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-height: 80px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.form {
|
&.form {
|
||||||
flex-grow: 1;
|
|
||||||
max-width: 420px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
margin: auto;
|
|
||||||
display: block;
|
|
||||||
max-height: 420px;
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ import { useState } from "preact/hooks";
|
||||||
|
|
||||||
import { Button, Preloader } from "@revoltchat/ui";
|
import { Button, Preloader } from "@revoltchat/ui";
|
||||||
|
|
||||||
import wideSVG from "/assets/wide.svg";
|
// import wideSVG from "/assets/wide.svg";
|
||||||
|
import background from "./assets/onboarding_background.svg";
|
||||||
|
|
||||||
import FormField from "../../../../pages/login/FormField";
|
import FormField from "../../../../pages/login/FormField";
|
||||||
import { takeError } from "../../../client/jsx/error";
|
import { takeError } from "../../../client/jsx/error";
|
||||||
|
@ -36,12 +37,9 @@ export function OnboardingModal({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.onboarding}>
|
<div className={styles.onboarding}>
|
||||||
|
<div className={styles.container}>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<h1>
|
<h1>{"Welcome to Revolt."}</h1>
|
||||||
<Text id="app.special.modals.onboarding.welcome" />
|
|
||||||
<br />
|
|
||||||
<img src={wideSVG} loading="eager" />
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.form}>
|
<div className={styles.form}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
|
@ -49,7 +47,15 @@ export function OnboardingModal({
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
<Text id="app.special.modals.onboarding.pick" />
|
{"It's time to choose a username."}
|
||||||
|
<br />
|
||||||
|
{
|
||||||
|
"Others will be able to find, recognise and mention you with this name, so choose wisely."
|
||||||
|
}
|
||||||
|
<br />
|
||||||
|
{
|
||||||
|
"You can change it at any time in your User Settings."
|
||||||
|
}
|
||||||
</p>
|
</p>
|
||||||
<form
|
<form
|
||||||
onSubmit={
|
onSubmit={
|
||||||
|
@ -65,14 +71,15 @@ export function OnboardingModal({
|
||||||
error={error}
|
error={error}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit">
|
<Button palette="accent">
|
||||||
<Text id="app.special.modals.actions.continue" />
|
{"Looks good!"}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div />
|
</div>
|
||||||
|
<img src={background} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,8 @@ import { ModalProps } from "../../types";
|
||||||
export const UserProfile = observer(
|
export const UserProfile = observer(
|
||||||
({
|
({
|
||||||
user_id,
|
user_id,
|
||||||
dummy,
|
isPlaceholder,
|
||||||
dummyProfile,
|
placeholderProfile,
|
||||||
...props
|
...props
|
||||||
}: ModalProps<"user_profile">) => {
|
}: ModalProps<"user_profile">) => {
|
||||||
const [profile, setProfile] = useState<
|
const [profile, setProfile] = useState<
|
||||||
|
@ -87,21 +87,21 @@ export const UserProfile = observer(
|
||||||
}, [user_id]);
|
}, [user_id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dummy) {
|
if (isPlaceholder) {
|
||||||
setProfile(dummyProfile);
|
setProfile(placeholderProfile);
|
||||||
}
|
}
|
||||||
}, [dummy, dummyProfile]);
|
}, [isPlaceholder, placeholderProfile]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dummy) return;
|
if (isPlaceholder) return;
|
||||||
if (session.state === "Online" && typeof mutual === "undefined") {
|
if (session.state === "Online" && typeof mutual === "undefined") {
|
||||||
setMutual(null);
|
setMutual(null);
|
||||||
user.fetchMutual().then(setMutual);
|
user.fetchMutual().then(setMutual);
|
||||||
}
|
}
|
||||||
}, [mutual, session.state, dummy, user]);
|
}, [mutual, session.state, isPlaceholder, user]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dummy) return;
|
if (isPlaceholder) return;
|
||||||
if (session.state === "Online" && typeof profile === "undefined") {
|
if (session.state === "Online" && typeof profile === "undefined") {
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ export const UserProfile = observer(
|
||||||
user.fetchProfile().then(setProfile).catch(noop);
|
user.fetchProfile().then(setProfile).catch(noop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [profile, session.state, dummy, user]);
|
}, [profile, session.state, isPlaceholder, user]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
|
@ -169,7 +169,8 @@ export const UserProfile = observer(
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
modalController.writeText(user.username)
|
modalController.writeText(user.username)
|
||||||
}>
|
}>
|
||||||
@{user.username}
|
{"@"}
|
||||||
|
{user.username}
|
||||||
</span>
|
</span>
|
||||||
</Localizer>
|
</Localizer>
|
||||||
{user.status?.text && (
|
{user.status?.text && (
|
||||||
|
@ -184,11 +185,11 @@ export const UserProfile = observer(
|
||||||
palette="accent"
|
palette="accent"
|
||||||
compact
|
compact
|
||||||
onClick={props.onClose}>
|
onClick={props.onClose}>
|
||||||
Add to server
|
{"Add to server" /* FIXME: i18n */}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{user.relationship === "Friend" && (
|
{(user.relationship === "Friend" || user.bot) && (
|
||||||
<Localizer>
|
<Localizer>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={
|
content={
|
||||||
|
@ -204,7 +205,7 @@ export const UserProfile = observer(
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Localizer>
|
</Localizer>
|
||||||
)}
|
)}
|
||||||
{user.relationship === "User" && !dummy && (
|
{user.relationship === "User" && !isPlaceholder && (
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.onClose?.();
|
props.onClose?.();
|
||||||
|
@ -237,11 +238,13 @@ export const UserProfile = observer(
|
||||||
</div>
|
</div>
|
||||||
{user.relationship !== "User" && (
|
{user.relationship !== "User" && (
|
||||||
<>
|
<>
|
||||||
|
{!user.bot && (
|
||||||
<div
|
<div
|
||||||
data-active={tab === "friends"}
|
data-active={tab === "friends"}
|
||||||
onClick={() => setTab("friends")}>
|
onClick={() => setTab("friends")}>
|
||||||
<Text id="app.special.popovers.user_profile.mutual_friends" />
|
<Text id="app.special.popovers.user_profile.mutual_friends" />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
data-active={tab === "groups"}
|
data-active={tab === "groups"}
|
||||||
onClick={() => setTab("groups")}>
|
onClick={() => setTab("groups")}>
|
||||||
|
@ -281,8 +284,9 @@ export const UserProfile = observer(
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{user.bot ? (
|
{user.bot ? (
|
||||||
<>
|
<>
|
||||||
|
{/* FIXME: this too */}
|
||||||
<div className={styles.category}>
|
<div className={styles.category}>
|
||||||
bot owner
|
{"bot owner"}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
@ -432,12 +436,12 @@ export const UserProfile = observer(
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (dummy) return <div>{children}</div>;
|
if (isPlaceholder) return <div>{children}</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
{...props}
|
{...props}
|
||||||
nonDismissable={dummy}
|
nonDismissable={isPlaceholder}
|
||||||
transparent
|
transparent
|
||||||
maxWidth="560px">
|
maxWidth="560px">
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<!-- The following background was created by Infi -->
|
||||||
|
<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="1921.2435514377348" xmlns="http://www.w3.org/2000/svg" height="421.46138650693956" id="screenshot-f4de8581-11da-11ed-b308-1b06919bb1d2" viewBox="-5 687.5386134930604 1921.2435514377348 421.46138650693956" style="-webkit-print-color-adjust: exact;" fill="none" version="1.1"><g id="shape-f4de8581-11da-11ed-b308-1b06919bb1d2"><g id="fills-f4de8581-11da-11ed-b308-1b06919bb1d2"><path rx="0" ry="0" d="M-5,906C-5,906,339,692,620,741C901,790,1313,868,1482,763C1651,658,1850,681,1899,722C1948,763,1877,1109,1877,1109L-5,1109L-5,906Z" style="fill: rgb(45, 45, 45); fill-opacity: 1;"/></g></g></svg>
|
After Width: | Height: | Size: 702 B |
|
@ -98,8 +98,8 @@ export type Modal = {
|
||||||
| {
|
| {
|
||||||
type: "user_profile";
|
type: "user_profile";
|
||||||
user_id: string;
|
user_id: string;
|
||||||
dummy?: boolean;
|
isPlaceholder?: boolean;
|
||||||
dummyProfile?: API.UserProfile;
|
placeholderProfile?: API.UserProfile;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "create_bot";
|
type: "create_bot";
|
||||||
|
|
|
@ -974,6 +974,10 @@ export default function ContextMenus() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// workaround to prevent button duplication
|
||||||
|
let hideIDButton;
|
||||||
|
if (sid && server) hideIDButton = true;
|
||||||
|
|
||||||
if (sid && server) {
|
if (sid && server) {
|
||||||
generateAction(
|
generateAction(
|
||||||
{
|
{
|
||||||
|
@ -1015,15 +1019,28 @@ export default function ContextMenus() {
|
||||||
"open_server_settings",
|
"open_server_settings",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// workaround to move this above the delete/leave button
|
||||||
|
generateAction(
|
||||||
|
{ action: "copy_id", id },
|
||||||
|
"copy_sid",
|
||||||
|
);
|
||||||
|
|
||||||
|
pushDivider();
|
||||||
if (userId === server.owner) {
|
if (userId === server.owner) {
|
||||||
generateAction(
|
generateAction(
|
||||||
{ action: "delete_server", target: server },
|
{ action: "delete_server", target: server },
|
||||||
"delete_server",
|
"delete_server",
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
"var(--error)",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
generateAction(
|
generateAction(
|
||||||
{ action: "leave_server", target: server },
|
{ action: "leave_server", target: server },
|
||||||
"leave_server",
|
"leave_server",
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
"var(--error)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1035,17 +1052,17 @@ export default function ContextMenus() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hideIDButton) {
|
||||||
generateAction(
|
generateAction(
|
||||||
{ action: "copy_id", id },
|
{ action: "copy_id", id },
|
||||||
sid
|
cid
|
||||||
? "copy_sid"
|
|
||||||
: cid
|
|
||||||
? "copy_cid"
|
? "copy_cid"
|
||||||
: message
|
: message
|
||||||
? "copy_mid"
|
? "copy_mid"
|
||||||
: "copy_uid",
|
: "copy_uid",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { action, makeAutoObservable, runInAction } from "mobx";
|
import { action, makeAutoObservable, runInAction } from "mobx";
|
||||||
import { Channel } from "revolt.js";
|
import { Channel, Nullable, toNullable } from "revolt.js";
|
||||||
import { Nullable, toNullable } from "revolt.js";
|
|
||||||
|
|
||||||
import type { ProduceType, VoiceUser } from "./Types";
|
import type { ProduceType, VoiceUser } from "./Types";
|
||||||
import type VoiceClient from "./VoiceClient";
|
import type VoiceClient from "./VoiceClient";
|
||||||
|
|
|
@ -5,15 +5,22 @@ import { mapToRecord } from "../../lib/conversion";
|
||||||
import Persistent from "../interfaces/Persistent";
|
import Persistent from "../interfaces/Persistent";
|
||||||
import Store from "../interfaces/Store";
|
import Store from "../interfaces/Store";
|
||||||
|
|
||||||
|
interface DraftObject {
|
||||||
|
content?: string;
|
||||||
|
masquerade?: {
|
||||||
|
avatar: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
export interface Data {
|
export interface Data {
|
||||||
drafts: Record<string, string>;
|
drafts: Record<string, DraftObject>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles storing draft (currently being written) messages.
|
* Handles storing draft (currently being written) messages.
|
||||||
*/
|
*/
|
||||||
export default class Draft implements Store, Persistent<Data> {
|
export default class Draft implements Store, Persistent<Data> {
|
||||||
private drafts: ObservableMap<string, string>;
|
private drafts: ObservableMap<string, DraftObject>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct new Draft store.
|
* Construct new Draft store.
|
||||||
|
@ -52,7 +59,10 @@ export default class Draft implements Store, Persistent<Data> {
|
||||||
* @param channel Channel ID
|
* @param channel Channel ID
|
||||||
*/
|
*/
|
||||||
@computed has(channel: string) {
|
@computed has(channel: string) {
|
||||||
return this.drafts.has(channel) && this.drafts.get(channel)!.length > 0;
|
return (
|
||||||
|
this.drafts.has(channel) &&
|
||||||
|
this.drafts.get(channel)!.content!.length > 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,7 +70,7 @@ export default class Draft implements Store, Persistent<Data> {
|
||||||
* @param channel Channel ID
|
* @param channel Channel ID
|
||||||
* @param content Draft content
|
* @param content Draft content
|
||||||
*/
|
*/
|
||||||
@action set(channel: string, content?: string) {
|
@action set(channel: string, content?: DraftObject) {
|
||||||
if (typeof content === "undefined") {
|
if (typeof content === "undefined") {
|
||||||
return this.clear(channel);
|
return this.clear(channel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,13 @@ export const EXPERIMENTS: {
|
||||||
[key in Experiment]: { title: string; description: string };
|
[key in Experiment]: { title: string; description: string };
|
||||||
} = {
|
} = {
|
||||||
dummy: {
|
dummy: {
|
||||||
title: "Dummy Experiment",
|
title: "Placeholder Experiment",
|
||||||
description: "This is a dummy experiment.",
|
description: "This is a placeholder experiment.",
|
||||||
},
|
},
|
||||||
offline_users: {
|
offline_users: {
|
||||||
title: "Re-enable offline users in large servers (>10k members)",
|
title: "Re-enable offline users in large servers (>10k members)",
|
||||||
description:
|
description:
|
||||||
"If you can take the performance hit (for example, you're on desktop), you can re-enable offline users for big servers such as Revolt Lounge.",
|
"If you can take the performance hit - for example, if you're on desktop - you can re-enable offline users for big servers such as the Revolt Lounge.",
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
title: "Experimental Plugin API",
|
title: "Experimental Plugin API",
|
||||||
|
@ -45,7 +45,7 @@ export const EXPERIMENTS: {
|
||||||
picker: {
|
picker: {
|
||||||
title: "Custom Emoji",
|
title: "Custom Emoji",
|
||||||
description:
|
description:
|
||||||
"This will enable a work-in-progress emoji picker, custom emoji settings and reaction picker.",
|
"This will enable a work-in-progress emoji picker, custom emoji settings and a reaction picker.",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ export interface ISettings {
|
||||||
"appearance:seasonal": boolean;
|
"appearance:seasonal": boolean;
|
||||||
"appearance:transparency": boolean;
|
"appearance:transparency": boolean;
|
||||||
"appearance:show_send_button": boolean;
|
"appearance:show_send_button": boolean;
|
||||||
|
"appearance:show_account_age": boolean;
|
||||||
|
|
||||||
"appearance:theme:base": "dark" | "light";
|
"appearance:theme:base": "dark" | "light";
|
||||||
"appearance:theme:overrides": Partial<Overrides>;
|
"appearance:theme:overrides": Partial<Overrides>;
|
||||||
|
@ -79,7 +80,7 @@ export default class Settings
|
||||||
*/
|
*/
|
||||||
@action set<T extends keyof ISettings>(key: T, value: ISettings[T]) {
|
@action set<T extends keyof ISettings>(key: T, value: ISettings[T]) {
|
||||||
// Emoji needs to be immediately applied.
|
// Emoji needs to be immediately applied.
|
||||||
if (key === 'appearance:emoji') {
|
if (key === "appearance:emoji") {
|
||||||
setGlobalEmojiPack(value as EmojiPack);
|
setGlobalEmojiPack(value as EmojiPack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ export default function App() {
|
||||||
)}
|
)}
|
||||||
{alert.dismissable !== false && (
|
{alert.dismissable !== false && (
|
||||||
<a onClick={() => setStatusBar(false)}>
|
<a onClick={() => setStatusBar(false)}>
|
||||||
<div className="button">Dismiss</div>
|
<div className="button">{"Dismiss"}</div>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { Wrench } from "@styled-icons/boxicons-solid";
|
||||||
|
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
import { Button } from "@revoltchat/ui";
|
||||||
|
|
||||||
import PaintCounter from "../../lib/PaintCounter";
|
import PaintCounter from "../../lib/PaintCounter";
|
||||||
import { TextReact } from "../../lib/i18n";
|
import { TextReact } from "../../lib/i18n";
|
||||||
|
|
||||||
|
@ -45,8 +47,15 @@ export default function Developer() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ padding: "16px" }}>
|
<div style={{ padding: "16px" }}>
|
||||||
<a style={"cursor: pointer;"} onClick={() => setCrash(true)}>click to crash app</a>
|
<Button palette="error" onClick={() => setCrash(true)}>
|
||||||
{crash && (window as any).sus.sus()}
|
Click to crash app
|
||||||
|
</Button>
|
||||||
|
{
|
||||||
|
crash &&
|
||||||
|
(
|
||||||
|
window as any
|
||||||
|
).sus.sus() /* this runs a function that doesn't exist */
|
||||||
|
}
|
||||||
{/*<span>
|
{/*<span>
|
||||||
<b>Voice Status:</b> {VoiceStatus[voice.status]}
|
<b>Voice Status:</b> {VoiceStatus[voice.status]}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -51,12 +51,11 @@ export default observer(() => {
|
||||||
state.settings.set("appearance:seasonal", !seasonalTheme);
|
state.settings.set("appearance:seasonal", !seasonalTheme);
|
||||||
|
|
||||||
const isDecember = !isTouchscreenDevice && new Date().getMonth() === 11;
|
const isDecember = !isTouchscreenDevice && new Date().getMonth() === 11;
|
||||||
|
const isOctober = !isTouchscreenDevice && new Date().getMonth() === 9
|
||||||
const snowflakes = useMemo(() => {
|
const snowflakes = useMemo(() => {
|
||||||
const flakes = [];
|
const flakes = [];
|
||||||
|
|
||||||
// Disable outside of December
|
if (isDecember) {
|
||||||
if (!isDecember) return [];
|
|
||||||
|
|
||||||
for (let i = 0; i < 15; i++) {
|
for (let i = 0; i < 15; i++) {
|
||||||
flakes.push("❄️");
|
flakes.push("❄️");
|
||||||
flakes.push("❄");
|
flakes.push("❄");
|
||||||
|
@ -68,6 +67,23 @@ export default observer(() => {
|
||||||
flakes.push("⛄");
|
flakes.push("⛄");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return flakes;
|
||||||
|
}
|
||||||
|
if (isOctober) {
|
||||||
|
for (let i = 0; i < 15; i++) {
|
||||||
|
flakes.push("🎃");
|
||||||
|
flakes.push("💀");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
flakes.push("👻");
|
||||||
|
flakes.push("⚰️");
|
||||||
|
flakes.push("🕷️");
|
||||||
|
}
|
||||||
|
|
||||||
|
return flakes;
|
||||||
|
}
|
||||||
|
|
||||||
return flakes;
|
return flakes;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 484 KiB |
|
@ -1,7 +1,6 @@
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Channel, API } from "revolt.js";
|
import { Channel, API, DEFAULT_PERMISSION_DIRECT_MESSAGE } from "revolt.js";
|
||||||
import { DEFAULT_PERMISSION_DIRECT_MESSAGE } from "revolt.js";
|
|
||||||
|
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
|
|
@ -24,7 +24,7 @@ export function Feedback() {
|
||||||
</CategoryButton>
|
</CategoryButton>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/revoltchat/revite/issues/new"
|
href="https://github.com/revoltchat/revite/issues/new/choose"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer">
|
rel="noreferrer">
|
||||||
<CategoryButton
|
<CategoryButton
|
||||||
|
@ -37,7 +37,7 @@ export function Feedback() {
|
||||||
</CategoryButton>
|
</CategoryButton>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/orgs/revoltchat/projects/1"
|
href="https://github.com/orgs/revoltchat/projects/3"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer">
|
rel="noreferrer">
|
||||||
<CategoryButton
|
<CategoryButton
|
||||||
|
@ -55,7 +55,7 @@ export function Feedback() {
|
||||||
action="chevron"
|
action="chevron"
|
||||||
icon={<Group size={24} />}
|
icon={<Group size={24} />}
|
||||||
description="You can report issues and discuss improvements with us directly here.">
|
description="You can report issues and discuss improvements with us directly here.">
|
||||||
Join Testers server.
|
{"Join the Revolt Lounge"}
|
||||||
</CategoryButton>
|
</CategoryButton>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -165,18 +165,22 @@ export function Native() {
|
||||||
title="I understand there's no going back."
|
title="I understand there's no going back."
|
||||||
description={
|
description={
|
||||||
<>
|
<>
|
||||||
This will change the app to the 'dev' branch,
|
{
|
||||||
instead loading the app from a local server on
|
"This will change the app to the 'dev' branch, instead loading the app from a local server on your machine."
|
||||||
your machine.
|
}
|
||||||
<br />
|
<br />
|
||||||
<b>
|
<b>
|
||||||
Without a server running,{" "}
|
{"Without a server running, "}
|
||||||
<span style={{ color: "var(--error)" }}>
|
<span style={{ color: "var(--error)" }}>
|
||||||
the app will not load!
|
{"the app will not load!"}
|
||||||
</span>
|
</span>
|
||||||
</b>
|
</b>
|
||||||
<br />
|
<br />
|
||||||
<code>yarn dev --port 3001</code>
|
{
|
||||||
|
"Make sure the app is available on port 3001 by running "
|
||||||
|
}
|
||||||
|
<code>{"yarn dev --port 3001 --host"}</code>
|
||||||
|
{"."}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -72,8 +72,8 @@ export const Profile = observer(() => {
|
||||||
<div className={styles.preview}>
|
<div className={styles.preview}>
|
||||||
<UserProfile
|
<UserProfile
|
||||||
user_id={client.user!._id}
|
user_id={client.user!._id}
|
||||||
dummy={true}
|
isPlaceholder={true}
|
||||||
dummyProfile={profile}
|
placeholderProfile={profile}
|
||||||
{...({} as any)}
|
{...({} as any)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Chrome, Android, Apple, Windows } from "@styled-icons/boxicons-logos";
|
import { Chrome, Android, Windows } from "@styled-icons/boxicons-logos";
|
||||||
import { HelpCircle, Desktop, LogOut } from "@styled-icons/boxicons-regular";
|
import { HelpCircle, Desktop, LogOut } from "@styled-icons/boxicons-regular";
|
||||||
import {
|
import {
|
||||||
Safari,
|
Safari,
|
||||||
|
@ -6,6 +6,7 @@ import {
|
||||||
Microsoftedge,
|
Microsoftedge,
|
||||||
Linux,
|
Linux,
|
||||||
Macos,
|
Macos,
|
||||||
|
Ios,
|
||||||
Opera,
|
Opera,
|
||||||
Samsung,
|
Samsung,
|
||||||
Windowsxp,
|
Windowsxp,
|
||||||
|
@ -99,7 +100,7 @@ export function Sessions() {
|
||||||
case /mac.*os/i.test(name):
|
case /mac.*os/i.test(name):
|
||||||
return <Macos size={14} />;
|
return <Macos size={14} />;
|
||||||
case /i(Pad)?os/i.test(name):
|
case /i(Pad)?os/i.test(name):
|
||||||
return <Apple size={14} />;
|
return <Ios size={14} />;
|
||||||
case /windows 7/i.test(name):
|
case /windows 7/i.test(name):
|
||||||
return <Windowsxp size={14} />;
|
return <Windowsxp size={14} />;
|
||||||
case /windows/i.test(name):
|
case /windows/i.test(name):
|
||||||
|
|
|
@ -96,14 +96,14 @@ export const Overview = observer(({ server }: Props) => {
|
||||||
<div className={styles.markdown}>
|
<div className={styles.markdown}>
|
||||||
<Markdown size="24" />
|
<Markdown size="24" />
|
||||||
<h5>
|
<h5>
|
||||||
Descriptions support Markdown formatting,{" "}
|
{"Server descriptions support Markdown formatting. "}
|
||||||
<a
|
<a
|
||||||
href="https://developers.revolt.chat/markdown"
|
href="https://support.revolt.chat/kb/interface/messages/formatting-your-messages"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer">
|
rel="noreferrer">
|
||||||
learn more here
|
{"Learn more here"}
|
||||||
</a>
|
</a>
|
||||||
.
|
{"."}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-size: 1.4em;
|
font-family: var(--monospace-font);
|
||||||
user-select: all;
|
user-select: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import { HelpCircle } from "@styled-icons/boxicons-solid";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Server } from "revolt.js";
|
import { Server } from "revolt.js";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
import { useMemo, useState } from "preact/hooks";
|
import { useMemo, useState } from "preact/hooks";
|
||||||
|
@ -16,6 +18,7 @@ import {
|
||||||
Category,
|
Category,
|
||||||
} from "@revoltchat/ui";
|
} from "@revoltchat/ui";
|
||||||
|
|
||||||
|
import Tooltip from "../../../components/common/Tooltip";
|
||||||
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
||||||
import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection";
|
import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection";
|
||||||
import { modalController } from "../../../controllers/modals/ModalController";
|
import { modalController } from "../../../controllers/modals/ModalController";
|
||||||
|
@ -53,6 +56,20 @@ export const Roles = observer(({ server }: Props) => {
|
||||||
// Consolidate all permissions that we can change right now.
|
// Consolidate all permissions that we can change right now.
|
||||||
const currentRoles = useRoles(server);
|
const currentRoles = useRoles(server);
|
||||||
|
|
||||||
|
const RoleId = styled.div`
|
||||||
|
gap: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tertiary-foreground);
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--tertiary-foreground);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PermissionsLayout
|
<PermissionsLayout
|
||||||
server={server}
|
server={server}
|
||||||
|
@ -147,6 +164,30 @@ export const Roles = observer(({ server }: Props) => {
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
|
<Category>{"Role ID"}</Category>
|
||||||
|
<RoleId>
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
"This is a unique identifier for this role."
|
||||||
|
}>
|
||||||
|
<HelpCircle size={16} />
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
<Text id="app.special.copy" />
|
||||||
|
}>
|
||||||
|
<a
|
||||||
|
onClick={() =>
|
||||||
|
modalController.writeText(
|
||||||
|
currentRole.id,
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
{currentRole.id}
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
|
</RoleId>
|
||||||
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<Category>
|
<Category>
|
||||||
<Text id="app.settings.permissions.role_colour" />
|
<Text id="app.settings.permissions.role_colour" />
|
||||||
|
|
50
yarn.lock
50
yarn.lock
|
@ -1590,7 +1590,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.5, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.8.4":
|
"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.5, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.8.4":
|
||||||
version: 7.15.3
|
version: 7.15.3
|
||||||
resolution: "@babel/runtime@npm:7.15.3"
|
resolution: "@babel/runtime@npm:7.15.3"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1617,6 +1617,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@babel/runtime@npm:^7.17.9":
|
||||||
|
version: 7.18.9
|
||||||
|
resolution: "@babel/runtime@npm:7.18.9"
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime: ^0.13.4
|
||||||
|
checksum: 36dd736baba7164e82b3cc9d43e081f0cb2d05ff867ad39cac515d99546cee75b7f782018b02a3dcf5f2ef3d27f319faa68965fdfec49d4912c60c6002353a2e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@babel/standalone@npm:^7.17.2":
|
"@babel/standalone@npm:^7.17.2":
|
||||||
version: 7.17.6
|
version: 7.17.6
|
||||||
resolution: "@babel/standalone@npm:7.17.6"
|
resolution: "@babel/standalone@npm:7.17.6"
|
||||||
|
@ -2020,13 +2029,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@hcaptcha/react-hcaptcha@npm:^0.3.6":
|
"@hcaptcha/react-hcaptcha@npm:^1.4.4":
|
||||||
version: 0.3.7
|
version: 1.4.4
|
||||||
resolution: "@hcaptcha/react-hcaptcha@npm:0.3.7"
|
resolution: "@hcaptcha/react-hcaptcha@npm:1.4.4"
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime": ^7.17.9
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ">= 16.3.0"
|
react: ">= 16.3.0"
|
||||||
react-dom: ">= 16.3.0"
|
react-dom: ">= 16.3.0"
|
||||||
checksum: 4a0ce88dd7a719cae2dc84255466a8636540287c2208f8fe46003a67c72f65509cabf8452cad73982a514cfce2e475d209a3e67cd41a559465f185fb4176a92f
|
checksum: 16b046702957f4ca5041c37f2a5012e07415469667fee0396b4764baa7ce0fe5a8577cf652b977732f026d745c999f7e1522bca3b3ca6effea5cfff189ddff2f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -2414,16 +2425,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@styled-icons/simple-icons@npm:^10.33.0":
|
"@styled-icons/simple-icons@npm:^10.45.0":
|
||||||
version: 10.37.0
|
version: 10.45.0
|
||||||
resolution: "@styled-icons/simple-icons@npm:10.37.0"
|
resolution: "@styled-icons/simple-icons@npm:10.45.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": ^7.14.8
|
"@babel/runtime": ^7.15.4
|
||||||
"@styled-icons/styled-icon": ^10.6.3
|
"@styled-icons/styled-icon": ^10.6.3
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: "*"
|
react: "*"
|
||||||
styled-components: "*"
|
styled-components: "*"
|
||||||
checksum: d94b94f6ad82aef50c69933f2f99d9ccdcadf3579f1ecd9fc5b5537ff1a2d7c0630579c4f1e0f73d6893a4e1cea4010d4ab927ba848a6bab7b1fba31e59c0f01
|
checksum: fda28f4ce59282916413ac2d638440a186f4ae2b1b5904c0e9695efdeec3849800a659f1292299d9afa45276e926f4110b6cbe9259dc38d9ffdc41ef0b4c0086
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -2692,7 +2703,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:^15.12.4":
|
"@types/node@npm:^15.14.9":
|
||||||
version: 15.14.9
|
version: 15.14.9
|
||||||
resolution: "@types/node@npm:15.14.9"
|
resolution: "@types/node@npm:15.14.9"
|
||||||
checksum: 49f7f0522a3af4b8389aee660e88426490cd54b86356672a1fedb49919a8797c00d090ec2dcc4a5df34edc2099d57fc2203d796c4e7fbd382f2022ccd789eee7
|
checksum: 49f7f0522a3af4b8389aee660e88426490cd54b86356672a1fedb49919a8797c00d090ec2dcc4a5df34edc2099d57fc2203d796c4e7fbd382f2022ccd789eee7
|
||||||
|
@ -2722,14 +2733,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/prismjs@npm:^1.16.5":
|
"@types/prismjs@npm:^1.16.6, @types/prismjs@npm:^1.26.0":
|
||||||
version: 1.16.6
|
|
||||||
resolution: "@types/prismjs@npm:1.16.6"
|
|
||||||
checksum: fcb489d19d21292ceffc661fd9c9aa8ba36bcd2835388fa85812aa60cdf14d4720ceb22be7a088aa753c48462e75bcd8191d178a085e4a8b0d3f34471d30d86a
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@types/prismjs@npm:^1.16.6":
|
|
||||||
version: 1.26.0
|
version: 1.26.0
|
||||||
resolution: "@types/prismjs@npm:1.26.0"
|
resolution: "@types/prismjs@npm:1.26.0"
|
||||||
checksum: cd5e7a6214c1f4213ec512a5fcf6d8fe37a56b813fc57ac95b5ff5ee074742bfdbd2f2730d9fd985205bf4586728e09baa97023f739e5aa1c9735a7c1ecbd11a
|
checksum: cd5e7a6214c1f4213ec512a5fcf6d8fe37a56b813fc57ac95b5ff5ee074742bfdbd2f2730d9fd985205bf4586728e09baa97023f739e5aa1c9735a7c1ecbd11a
|
||||||
|
@ -3681,7 +3685,7 @@ __metadata:
|
||||||
"@fontsource/space-mono": ^4.4.5
|
"@fontsource/space-mono": ^4.4.5
|
||||||
"@fontsource/ubuntu": ^4.4.5
|
"@fontsource/ubuntu": ^4.4.5
|
||||||
"@fontsource/ubuntu-mono": ^4.4.5
|
"@fontsource/ubuntu-mono": ^4.4.5
|
||||||
"@hcaptcha/react-hcaptcha": ^0.3.6
|
"@hcaptcha/react-hcaptcha": ^1.4.4
|
||||||
"@insertish/vite-plugin-babel-macros": ^1.0.5
|
"@insertish/vite-plugin-babel-macros": ^1.0.5
|
||||||
"@preact/preset-vite": ^2.0.0
|
"@preact/preset-vite": ^2.0.0
|
||||||
"@revoltchat/ui": ^1.0.77
|
"@revoltchat/ui": ^1.0.77
|
||||||
|
@ -3689,7 +3693,7 @@ __metadata:
|
||||||
"@styled-icons/boxicons-logos": ^10.38.0
|
"@styled-icons/boxicons-logos": ^10.38.0
|
||||||
"@styled-icons/boxicons-regular": ^10.38.0
|
"@styled-icons/boxicons-regular": ^10.38.0
|
||||||
"@styled-icons/boxicons-solid": ^10.38.0
|
"@styled-icons/boxicons-solid": ^10.38.0
|
||||||
"@styled-icons/simple-icons": ^10.33.0
|
"@styled-icons/simple-icons": ^10.45.0
|
||||||
"@tippyjs/react": 4.2.6
|
"@tippyjs/react": 4.2.6
|
||||||
"@traptitech/markdown-it-katex": ^3.4.3
|
"@traptitech/markdown-it-katex": ^3.4.3
|
||||||
"@traptitech/markdown-it-spoiler": ^1.1.6
|
"@traptitech/markdown-it-spoiler": ^1.1.6
|
||||||
|
@ -3697,9 +3701,9 @@ __metadata:
|
||||||
"@types/lodash": ^4
|
"@types/lodash": ^4
|
||||||
"@types/lodash.defaultsdeep": ^4.6.6
|
"@types/lodash.defaultsdeep": ^4.6.6
|
||||||
"@types/lodash.isequal": ^4.5.5
|
"@types/lodash.isequal": ^4.5.5
|
||||||
"@types/node": ^15.12.4
|
"@types/node": ^15.14.9
|
||||||
"@types/preact-i18n": ^2.3.0
|
"@types/preact-i18n": ^2.3.0
|
||||||
"@types/prismjs": ^1.16.5
|
"@types/prismjs": ^1.26.0
|
||||||
"@types/react-beautiful-dnd": ^13
|
"@types/react-beautiful-dnd": ^13
|
||||||
"@types/react-helmet": ^6.1.1
|
"@types/react-helmet": ^6.1.1
|
||||||
"@types/react-router-dom": ^5.1.7
|
"@types/react-router-dom": ^5.1.7
|
||||||
|
|
Loading…
Reference in a new issue