mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-23 15:40:57 -05:00
Compare commits
8 commits
c6daf0592f
...
b2985ae155
Author | SHA1 | Date | |
---|---|---|---|
|
b2985ae155 | ||
|
5de18192b2 | ||
|
ef4218d12b | ||
|
df4f6578f7 | ||
|
cd4d8eb96d | ||
|
c972e6813f | ||
|
61304f18c2 | ||
|
ffee147aed |
16 changed files with 139 additions and 58 deletions
4
.env
4
.env
|
@ -1,5 +1,5 @@
|
||||||
# VITE_API_URL=https://api.revolt.chat
|
# VITE_API_URL=https://api.revolt.chat
|
||||||
VITE_API_URL=https://app.revolt.chat/api
|
# VITE_API_URL=https://app.revolt.chat/api
|
||||||
# VITE_API_URL=http://local.revolt.chat:8000
|
# VITE_API_URL=http://local.revolt.chat:8000
|
||||||
# VITE_API_URL=https://revolt.chat/api
|
VITE_API_URL=https://revolt.chat/api
|
||||||
VITE_THEMES_URL=https://themes.revolt.chat
|
VITE_THEMES_URL=https://themes.revolt.chat
|
||||||
|
|
|
@ -106,9 +106,9 @@ export default observer(() => {
|
||||||
"scrollbar-thumb",
|
"scrollbar-thumb",
|
||||||
"scrollbar-track",
|
"scrollbar-track",
|
||||||
"status-online",
|
"status-online",
|
||||||
"status-away",
|
"status-idle",
|
||||||
|
"status-focus",
|
||||||
"status-busy",
|
"status-busy",
|
||||||
"status-streaming",
|
|
||||||
"status-invisible",
|
"status-invisible",
|
||||||
"success",
|
"success",
|
||||||
"warning",
|
"warning",
|
||||||
|
|
|
@ -68,12 +68,11 @@ export function PermissionSelect({
|
||||||
|
|
||||||
return "Neutral";
|
return "Neutral";
|
||||||
}
|
}
|
||||||
if (Long.fromNumber(value).and(permission).eq(permission)) {
|
if (Long.fromNumber(value).and(permission).eq(permission)) {
|
||||||
return "Allow";
|
return "Allow";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Neutral";
|
|
||||||
|
|
||||||
|
return "Neutral";
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
function onSwitch(state: State) {
|
function onSwitch(state: State) {
|
||||||
|
|
|
@ -30,10 +30,9 @@ export type Variables =
|
||||||
| "tertiary-foreground"
|
| "tertiary-foreground"
|
||||||
| "tooltip"
|
| "tooltip"
|
||||||
| "status-online"
|
| "status-online"
|
||||||
| "status-away"
|
| "status-idle"
|
||||||
| "status-focus"
|
| "status-focus"
|
||||||
| "status-busy"
|
| "status-busy"
|
||||||
| "status-streaming"
|
|
||||||
| "status-invisible";
|
| "status-invisible";
|
||||||
|
|
||||||
// While this isn't used, it'd be good to keep this up to date as a reference or for future use
|
// While this isn't used, it'd be good to keep this up to date as a reference or for future use
|
||||||
|
@ -283,10 +282,9 @@ export const PRESETS: Record<string, Theme> = {
|
||||||
"tertiary-background": "#4D4D4D",
|
"tertiary-background": "#4D4D4D",
|
||||||
"tertiary-foreground": "#3a3a3a",
|
"tertiary-foreground": "#3a3a3a",
|
||||||
"status-online": "#3ABF7E",
|
"status-online": "#3ABF7E",
|
||||||
"status-away": "#F39F00",
|
"status-idle": "#F39F00",
|
||||||
"status-focus": "#4799F0",
|
"status-focus": "#4799F0",
|
||||||
"status-busy": "#F84848",
|
"status-busy": "#F84848",
|
||||||
"status-streaming": "#977EFF",
|
|
||||||
"status-invisible": "#A5A5A5",
|
"status-invisible": "#A5A5A5",
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
|
@ -311,10 +309,9 @@ export const PRESETS: Record<string, Theme> = {
|
||||||
"tertiary-background": "#4D4D4D",
|
"tertiary-background": "#4D4D4D",
|
||||||
"tertiary-foreground": "#848484",
|
"tertiary-foreground": "#848484",
|
||||||
"status-online": "#3ABF7E",
|
"status-online": "#3ABF7E",
|
||||||
"status-away": "#F39F00",
|
"status-idle": "#F39F00",
|
||||||
"status-focus": "#4799F0",
|
"status-focus": "#4799F0",
|
||||||
"status-busy": "#F84848",
|
"status-busy": "#F84848",
|
||||||
"status-streaming": "#977EFF",
|
|
||||||
"status-invisible": "#A5A5A5",
|
"status-invisible": "#A5A5A5",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ export function takeError(error: any): string {
|
||||||
case 429:
|
case 429:
|
||||||
return "TooManyRequests";
|
return "TooManyRequests";
|
||||||
case 401:
|
case 401:
|
||||||
return "Unauthorized"
|
return "Unauthorized";
|
||||||
case 403:
|
case 403:
|
||||||
return "Forbidden";
|
return "Forbidden";
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { IconButton, Preloader } from "@revoltchat/ui";
|
||||||
import { determineFileSize } from "../../../../lib/fileSize";
|
import { determineFileSize } from "../../../../lib/fileSize";
|
||||||
|
|
||||||
import { modalController } from "../../../modals/ModalController";
|
import { modalController } from "../../../modals/ModalController";
|
||||||
import { useClient } from "../../ClientController";
|
import { clientController, useClient } from "../../ClientController";
|
||||||
import { takeError } from "../error";
|
import { takeError } from "../error";
|
||||||
|
|
||||||
type BehaviourType =
|
type BehaviourType =
|
||||||
|
@ -67,9 +67,16 @@ export async function uploadFile(
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
formData.append("file", file);
|
||||||
|
|
||||||
|
const client = clientController.getActiveSession()?.client;
|
||||||
|
const sesToken =
|
||||||
|
typeof client?.session === "string"
|
||||||
|
? client.session
|
||||||
|
: client?.session?.token;
|
||||||
|
|
||||||
const res = await Axios.post(`${autumnURL}/${tag}`, formData, {
|
const res = await Axios.post(`${autumnURL}/${tag}`, formData, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "multipart/form-data",
|
"Content-Type": "multipart/form-data",
|
||||||
|
"X-Session-Token": sesToken,
|
||||||
},
|
},
|
||||||
...config,
|
...config,
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,10 +7,10 @@ import { ModalForm } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { noopAsync } from "../../../lib/js";
|
import { noopAsync } from "../../../lib/js";
|
||||||
|
|
||||||
|
import { IS_REVOLT } from "../../../version";
|
||||||
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
|
||||||
|
@ -79,7 +79,9 @@ 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(
|
||||||
IS_REVOLT ? `https://rvlt.gg/${code}` : `${window.location.host}/invite/${code}`
|
IS_REVOLT
|
||||||
|
? `https://rvlt.gg/${code}`
|
||||||
|
: `${window.location.host}/invite/${code}`,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -2,29 +2,32 @@ import { ChevronRight, Trash } from "@styled-icons/boxicons-regular";
|
||||||
import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
|
import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
|
||||||
import { isFirefox } from "react-device-detect";
|
import { isFirefox } from "react-device-detect";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { Channel, Message, Server, User, API, Permission, UserPermission, Member } from "revolt.js";
|
import {
|
||||||
|
Channel,
|
||||||
|
Message,
|
||||||
|
Server,
|
||||||
|
User,
|
||||||
|
API,
|
||||||
|
Permission,
|
||||||
|
UserPermission,
|
||||||
|
Member,
|
||||||
|
} from "revolt.js";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ContextMenuWithData,
|
||||||
import { ContextMenuWithData, MenuItem, openContextMenu } from "preact-context-menu";
|
MenuItem,
|
||||||
|
openContextMenu,
|
||||||
|
} from "preact-context-menu";
|
||||||
import { Text } from "preact-i18n";
|
import { Text } from "preact-i18n";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { Column, IconButton, LineDivider } from "@revoltchat/ui";
|
import { Column, IconButton, LineDivider } from "@revoltchat/ui";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { useApplicationState } from "../mobx/State";
|
import { useApplicationState } from "../mobx/State";
|
||||||
import { QueuedMessage } from "../mobx/stores/MessageQueue";
|
import { QueuedMessage } from "../mobx/stores/MessageQueue";
|
||||||
import { NotificationState } from "../mobx/stores/NotificationOptions";
|
import { NotificationState } from "../mobx/stores/NotificationOptions";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import CMNotifications from "./contextmenu/CMNotifications";
|
import CMNotifications from "./contextmenu/CMNotifications";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import Tooltip from "../components/common/Tooltip";
|
import Tooltip from "../components/common/Tooltip";
|
||||||
import UserStatus from "../components/common/user/UserStatus";
|
import UserStatus from "../components/common/user/UserStatus";
|
||||||
import { useSession } from "../controllers/client/ClientController";
|
import { useSession } from "../controllers/client/ClientController";
|
||||||
|
@ -33,7 +36,6 @@ import { modalController } from "../controllers/modals/ModalController";
|
||||||
import { internalEmit } from "./eventEmitter";
|
import { internalEmit } from "./eventEmitter";
|
||||||
import { getRenderer } from "./renderer/Singleton";
|
import { getRenderer } from "./renderer/Singleton";
|
||||||
|
|
||||||
|
|
||||||
interface ContextMenuData {
|
interface ContextMenuData {
|
||||||
user?: string;
|
user?: string;
|
||||||
server?: string;
|
server?: string;
|
||||||
|
|
|
@ -83,10 +83,9 @@ export default class SAudio {
|
||||||
if (this.cache.has(path)) {
|
if (this.cache.has(path)) {
|
||||||
return this.cache.get(path)!;
|
return this.cache.get(path)!;
|
||||||
}
|
}
|
||||||
const el = new Audio(path);
|
const el = new Audio(path);
|
||||||
this.cache.set(path, el);
|
this.cache.set(path, el);
|
||||||
return el;
|
return el;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadCache() {
|
loadCache() {
|
||||||
|
@ -100,7 +99,7 @@ export default class SAudio {
|
||||||
try {
|
try {
|
||||||
audio.play();
|
audio.play();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Hit error while playing", `${sound }:`, err);
|
console.error("Hit error while playing", `${sound}:`, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ export default class STheme {
|
||||||
for (const key of Object.keys(variables)) {
|
for (const key of Object.keys(variables)) {
|
||||||
const value = variables[key];
|
const value = variables[key];
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
variables[`${key }-contrast`] = getContrastingColour(value);
|
variables[`${key}-contrast`] = getContrastingColour(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Hash } from "@styled-icons/boxicons-regular";
|
import { Hash } from "@styled-icons/boxicons-regular";
|
||||||
import { Ghost } from "@styled-icons/boxicons-solid";
|
import { Ghost } from "@styled-icons/boxicons-solid";
|
||||||
|
import dayjs from "dayjs";
|
||||||
import { reaction } from "mobx";
|
import { reaction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Redirect, useParams } from "react-router-dom";
|
import { Redirect, useParams } from "react-router-dom";
|
||||||
|
@ -163,6 +164,7 @@ const TextChannel = observer(({ channel }: { channel: ChannelI }) => {
|
||||||
|
|
||||||
const checkUnread = () =>
|
const checkUnread = () =>
|
||||||
channel.unread &&
|
channel.unread &&
|
||||||
|
document.hasFocus() &&
|
||||||
channel.client.unreads!.markRead(
|
channel.client.unreads!.markRead(
|
||||||
channel._id,
|
channel._id,
|
||||||
channel.last_message_id!,
|
channel.last_message_id!,
|
||||||
|
@ -176,6 +178,46 @@ const TextChannel = observer(({ channel }: { channel: ChannelI }) => {
|
||||||
);
|
);
|
||||||
}, [channel]);
|
}, [channel]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let lastSubscribed: number | undefined;
|
||||||
|
function subscribe() {
|
||||||
|
if (document.hasFocus()) {
|
||||||
|
if (
|
||||||
|
!lastSubscribed ||
|
||||||
|
dayjs().subtract(10, "minutes").isAfter(lastSubscribed)
|
||||||
|
) {
|
||||||
|
lastSubscribed = +new Date();
|
||||||
|
channel.server?.subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger logic every minute
|
||||||
|
const subTimer = setInterval(subscribe, 60e3);
|
||||||
|
subscribe();
|
||||||
|
|
||||||
|
function onFocus() {
|
||||||
|
// Mark channel as read if it's unread
|
||||||
|
if (channel.unread) {
|
||||||
|
channel.client.unreads!.markRead(
|
||||||
|
channel._id,
|
||||||
|
channel.last_message_id!,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe to channel if expired
|
||||||
|
subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener("focus", onFocus);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
removeEventListener("focus", onFocus);
|
||||||
|
clearInterval(subTimer);
|
||||||
|
};
|
||||||
|
}, [channel]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AgeGate
|
<AgeGate
|
||||||
type="channel"
|
type="channel"
|
||||||
|
|
|
@ -51,7 +51,7 @@ 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 isOctober = !isTouchscreenDevice && new Date().getMonth() === 9;
|
||||||
const snowflakes = useMemo(() => {
|
const snowflakes = useMemo(() => {
|
||||||
const flakes: string[] = [];
|
const flakes: string[] = [];
|
||||||
|
|
||||||
|
|
|
@ -103,10 +103,43 @@ export const Members = ({ server }: Props) => {
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
server
|
function fetch() {
|
||||||
.fetchMembers()
|
server
|
||||||
.then((data) => data.members)
|
.fetchMembers()
|
||||||
.then(setData);
|
.then((data) => data.members)
|
||||||
|
.then(setData);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch();
|
||||||
|
|
||||||
|
// Members may be invalidated if we stop receiving events
|
||||||
|
// This is not very accurate, this should be tracked within
|
||||||
|
// revolt.js so we know the true validity.
|
||||||
|
let valid = true,
|
||||||
|
invalidationTimer: number;
|
||||||
|
|
||||||
|
function waitToInvalidate() {
|
||||||
|
invalidationTimer = setTimeout(() => {
|
||||||
|
valid = false;
|
||||||
|
}, 15 * 60e3) as never; // 15 minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelInvalidation() {
|
||||||
|
if (!valid) {
|
||||||
|
fetch();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(invalidationTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener("blur", waitToInvalidate);
|
||||||
|
addEventListener("focus", cancelInvalidation);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
removeEventListener("blur", waitToInvalidate);
|
||||||
|
removeEventListener("focus", cancelInvalidation);
|
||||||
|
};
|
||||||
}, [server, setData]);
|
}, [server, setData]);
|
||||||
|
|
||||||
const members = useMemo(
|
const members = useMemo(
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.idle {
|
&.idle {
|
||||||
background: var(--status-away);
|
background: var(--status-idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.focus {
|
&.focus {
|
||||||
|
|
|
@ -29,7 +29,7 @@ precacheAndRoute(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key of locale_keys) {
|
for (const key of locale_keys) {
|
||||||
if (fn.startsWith(`${key }.`)) {
|
if (fn.startsWith(`${key}.`)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue