1 Commits

Author SHA1 Message Date
Lea
fe0d0501fa fix: delete gigachad 2023-08-22 15:25:10 +02:00
36 changed files with 270 additions and 523 deletions

4
.env
View File

@@ -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=http://local.revolt.chat:8000
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=https://revolt.chat/api
VITE_THEMES_URL=https://themes.revolt.chat VITE_THEMES_URL=https://themes.revolt.chat

View File

@@ -1,6 +1,6 @@
## Please make sure to check the following tasks before opening and submitting a PR ## Please make sure to check the following tasks before opening and submitting a PR
* [ ] I understand and have followed the [contribution guide](https://developers.revolt.chat/contrib.html) * [ ] I understand and have followed the [contribution guide](https://github.com/revoltchat/revolt/discussions/282)
* [ ] I have tested my changes locally and they are working as intended * [ ] I have tested my changes locally and they are working as intended
* [ ] These changes do not have any notable side effects on other Revolt projects * [ ] These changes do not have any notable side effects on other Revolt projects
* [ ] (optional) I have opened a pull request on [the translation repository](https://github.com/revoltchat/translations) * [ ] (optional) I have opened a pull request on [the translation repository](https://github.com/revoltchat/translations)

View File

@@ -30,18 +30,55 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
architecture: [linux/amd64]
steps:
- name: Checkout
uses: actions/checkout@v2
with:
submodules: "recursive"
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache/${{ matrix.architecture }}
key: ${{ runner.os }}-buildx-${{ matrix.architecture }}-${{ github.sha }}
- name: Build
uses: docker/build-push-action@v2
with:
context: .
platforms: ${{ matrix.architecture }}
cache-from: type=local,src=/tmp/.buildx-cache/${{ matrix.architecture }}
cache-to: type=local,dest=/tmp/.buildx-cache-new/${{ matrix.architecture }},mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache/${{ matrix.architecture }}
mv /tmp/.buildx-cache-new/${{ matrix.architecture }} /tmp/.buildx-cache/${{ matrix.architecture }}
publish: publish:
needs: [test]
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
submodules: "recursive" submodules: "recursive"
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v1
- name: Cache amd64 Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache/linux/amd64
key: ${{ runner.os }}-buildx-linux/amd64-${{ github.sha }}
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v3 uses: docker/metadata-action@v3
@@ -49,22 +86,26 @@ jobs:
images: revoltchat/client, ghcr.io/revoltchat/client images: revoltchat/client, ghcr.io/revoltchat/client
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1 uses: docker/login-action@v1
if: github.event_name != 'pull_request'
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to Github Container Registry - name: Login to Github Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v1
if: github.event_name != 'pull_request'
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and publish - name: Build and publish
uses: docker/build-push-action@v6 uses: docker/build-push-action@v2
with: with:
context: . context: .
push: ${{ github.event_name != 'pull_request' }} push: true
platforms: linux/amd64 platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache/linux/amd64
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache

16
.github/workflows/mirroring.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Mirroring
on:
push:
branches:
- "master"
jobs:
to_gitlab:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v1
- uses: pixta-dev/repository-mirroring-action@v1
with:
target_repo_url: git@gitlab.com:insert/revolt-vite.git
ssh_private_key: ${{ secrets.GITLAB_SSH_PRIVATE_KEY }}

View File

@@ -15,7 +15,7 @@ jobs:
gh api graphql -f query=' gh api graphql -f query='
query { query {
organization(login: "revoltchat"){ organization(login: "revoltchat"){
projectV2(number: 5) { projectV2(number: 3) {
id id
fields(first:20) { fields(first:20) {
nodes { nodes {
@@ -35,7 +35,7 @@ jobs:
echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'INCOMING_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="🆕 Untriaged") |.id' project_data.json) >> $GITHUB_ENV echo 'INCOMING_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Incoming PRs") |.id' project_data.json) >> $GITHUB_ENV
- name: Add PR to project - name: Add PR to project
env: env:

View File

@@ -1,30 +1,3 @@
# Deprecation Notice
This project is deprecated, however it still may receive maintenance updates.
PRs for small fixes are more than welcome.
## Deploying a new release
Ensure `.env.local` points to `https://app.revolt.chat/api`.
```bash
cd ~/deployments/revite
git pull
git submodule update
# check:
git status
export REVOLT_SAAS_BRANCH=revite/main
export REMOTE=root@production
scripts/publish.sh
# SSH in and restart revite:
ssh $REMOTE
tmux a -t 4
```
# Revite # Revite
## Description ## Description

2
external/lang vendored

View File

@@ -8,10 +8,10 @@ if [ -z "$REMOTE" ]; then
fi fi
# Remote Directory # Remote Directory
REMOTE_DIR=/root/deployments/revite REMOTE_DIR=/root/revite
# Post-install script # Post-install script
POST_INSTALL="" POST_INSTALL="pm2 restart revite"
# Assets # Assets
export REVOLT_SAAS=https://github.com/revoltchat/assets export REVOLT_SAAS=https://github.com/revoltchat/assets

View File

@@ -1848,109 +1848,107 @@ export const emojiDictionary = {
england: "🏴󠁧󠁢󠁥󠁮󠁧󠁿", england: "🏴󠁧󠁢󠁥󠁮󠁧󠁿",
scotland: "🏴󠁧󠁢󠁳󠁣󠁴󠁿", scotland: "🏴󠁧󠁢󠁳󠁣󠁴󠁿",
wales: "🏴󠁧󠁢󠁷󠁬󠁳󠁿", wales: "🏴󠁧󠁢󠁷󠁬󠁳󠁿",
// ...{ ...{
// 1984: "custom:1984.gif", 1984: "custom:1984.gif",
// KekW: "custom:KekW.png", KekW: "custom:KekW.png",
// amogus: "custom:amogus.gif", amogus: "custom:amogus.gif",
// awaa: "custom:awaa.png", awaa: "custom:awaa.png",
// boohoo: "custom:boohoo.png", boohoo: "custom:boohoo.png",
// boohoo_goes_hard: "custom:boohoo_goes_hard.png", boohoo_goes_hard: "custom:boohoo_goes_hard.png",
// boohoo_shaken: "custom:boohoo_shaken.png", boohoo_shaken: "custom:boohoo_shaken.png",
// cat_arrival: "custom:cat_arrival.gif", cat_arrival: "custom:cat_arrival.gif",
// cat_awson: "custom:cat_awson.png", cat_awson: "custom:cat_awson.png",
// cat_blob: "custom:cat_blob.png", cat_blob: "custom:cat_blob.png",
// cat_bonk: "custom:cat_bonk.png", cat_bonk: "custom:cat_bonk.png",
// cat_concern: "custom:cat_concern.png", cat_concern: "custom:cat_concern.png",
// cat_fast: "custom:cat_fast.gif", cat_fast: "custom:cat_fast.gif",
// cat_kitty: "custom:cat_kitty.png", cat_kitty: "custom:cat_kitty.png",
// cat_lick: "custom:cat_lick.gif", cat_lick: "custom:cat_lick.gif",
// cat_not_like: "custom:cat_not_like.png", cat_not_like: "custom:cat_not_like.png",
// cat_put: "custom:cat_put.gif", cat_put: "custom:cat_put.gif",
// cat_pwease: "custom:cat_pwease.png", cat_pwease: "custom:cat_pwease.png",
// cat_rage: "custom:cat_rage.png", cat_rage: "custom:cat_rage.png",
// cat_sad: "custom:cat_sad.png", cat_sad: "custom:cat_sad.png",
// cat_snuff: "custom:cat_snuff.gif", cat_snuff: "custom:cat_snuff.gif",
// cat_spin: "custom:cat_spin.gif", cat_spin: "custom:cat_spin.gif",
// cat_squish: "custom:cat_squish.gif", cat_squish: "custom:cat_squish.gif",
// cat_stare: "custom:cat_stare.gif", cat_stare: "custom:cat_stare.gif",
// cat_steal: "custom:cat_steal.gif", cat_steal: "custom:cat_steal.gif",
// cat_sussy: "custom:cat_sussy.gif", cat_sussy: "custom:cat_sussy.gif",
// clueless: "custom:clueless.png", clueless: "custom:clueless.png",
// death: "custom:death.gif", death: "custom:death.gif",
// developers: "custom:developers.gif", developers: "custom:developers.gif",
// fastwawa: "custom:fastwawa.gif", fastwawa: "custom:fastwawa.gif",
// ferris: "custom:ferris.png", ferris: "custom:ferris.png",
// ferris_bongo: "custom:ferris_bongo.gif", ferris_bongo: "custom:ferris_bongo.gif",
// ferris_nom: "custom:ferris_nom.png", ferris_nom: "custom:ferris_nom.png",
// ferris_pensive: "custom:ferris_pensive.png", ferris_pensive: "custom:ferris_pensive.png",
// ferris_unsafe: "custom:ferris_unsafe.png", ferris_unsafe: "custom:ferris_unsafe.png",
// flesh: "custom:flesh.png", flesh: "custom:flesh.png",
// flooshed: "custom:flooshed.png", flooshed: "custom:flooshed.png",
// flosh: "custom:flosh.png", flosh: "custom:flosh.png",
// flushee: "custom:flushee.png", flushee: "custom:flushee.png",
// forgor: "custom:forgor.png", forgor: "custom:forgor.png",
// hollow: "custom:hollow.png", hollow: "custom:hollow.png",
// john: "custom:john.png", john: "custom:john.png",
// lightspeed: "custom:lightspeed.png", lightspeed: "custom:lightspeed.png",
// little_guy: "custom:little_guy.png", little_guy: "custom:little_guy.png",
// lmaoooo: "custom:lmaoooo.gif", lmaoooo: "custom:lmaoooo.gif",
// lol: "custom:lol.png", lol: "custom:lol.png",
// looking: "custom:looking.gif", looking: "custom:looking.gif",
// marie: "custom:marie.png", marie: "custom:marie.png",
// marie_furret: "custom:marie_furret.gif", marie_furret: "custom:marie_furret.gif",
// marie_smug: "custom:marie_smug.png", marie_smug: "custom:marie_smug.png",
// megumin: "custom:megumin.png", megumin: "custom:megumin.png",
// michi_above: "custom:michi_above.png", michi_above: "custom:michi_above.png",
// michi_awww: "custom:michi_awww.gif", michi_awww: "custom:michi_awww.gif",
// michi_drag: "custom:michi_drag.gif", michi_drag: "custom:michi_drag.gif",
// michi_flustered: "custom:michi_flustered.png", michi_flustered: "custom:michi_flustered.png",
// michi_glare: "custom:michi_glare.png", michi_glare: "custom:michi_glare.png",
// michi_sus: "custom:michi_sus.png", michi_sus: "custom:michi_sus.png",
// monkaS: "custom:monkaS.png", monkaS: "custom:monkaS.png",
// monkaStare: "custom:monkaStare.png", monkaStare: "custom:monkaStare.png",
// monkey_grr: "custom:monkey_grr.png", monkey_grr: "custom:monkey_grr.png",
// monkey_pensive: "custom:monkey_pensive.png", monkey_pensive: "custom:monkey_pensive.png",
// monkey_zany: "custom:monkey_zany.png", monkey_zany: "custom:monkey_zany.png",
// nazu_sit: "custom:nazu_sit.png", nazu_sit: "custom:nazu_sit.png",
// nazu_sus: "custom:nazu_sus.png", nazu_sus: "custom:nazu_sus.png",
// ok_and: "custom:ok_and.gif", ok_and: "custom:ok_and.gif",
// owo: "custom:owo.png", owo: "custom:owo.png",
// pat: "custom:pat.png", pat: "custom:pat.png",
// pointThink: "custom:pointThink.png", pointThink: "custom:pointThink.png",
// rainbowHype: "custom:rainbowHype.gif", rainbowHype: "custom:rainbowHype.gif",
// rawr: "custom:rawr.png", rawr: "custom:rawr.png",
// rember: "custom:rember.png", rember: "custom:rember.png",
// revolt: "custom:revolt.png", revolt: "custom:revolt.png",
// sickly: "custom:sickly.png", sickly: "custom:sickly.png",
// stare: "custom:stare.png", stare: "custom:stare.png",
// tfyoulookingat: "custom:tfyoulookingat.png", tfyoulookingat: "custom:tfyoulookingat.png",
// thanks: "custom:thanks.png", thanks: "custom:thanks.png",
// thonk: "custom:thonk.png", thonk: "custom:thonk.png",
// trol: "custom:trol.png", trol: "custom:trol.png",
// troll_smile: "custom:troll_smile.gif", troll_smile: "custom:troll_smile.gif",
// uber: "custom:uber.png", uber: "custom:uber.png",
// ubertroll: "custom:ubertroll.png", ubertroll: "custom:ubertroll.png",
// verycool: "custom:verycool.png", verycool: "custom:verycool.png",
// verygood: "custom:verygood.png", verygood: "custom:verygood.png",
// wawafast: "custom:wawafast.gif", wawafast: "custom:wawafast.gif",
// wawastance: "custom:wawastance.png", wawastance: "custom:wawastance.png",
// yeahokayyy: "custom:yeahokayyy.png", yeahokayyy: "custom:yeahokayyy.png",
// yed: "custom:yed.png", yed: "custom:yed.png",
// yems: "custom:yems.png", yems: "custom:yems.png",
// michael: "custom:michael.gif", michael: "custom:michael.gif",
// charle: "custom:charle.gif", charle: "custom:charle.gif",
// sadge: "custom:sadge.webp", sadge: "custom:sadge.webp",
// sus: "custom:sus.webp", sus: "custom:sus.webp",
// chade: "custom:chade.gif", sippy: "custom:sippy.webp",
// gigachad: "custom:gigachad.webp", ayame_heart: "custom:ayame_heart.png",
// sippy: "custom:sippy.webp", catgirl_peek: "custom:catgirl_peek.png",
// ayame_heart: "custom:ayame_heart.png", girl_happy: "custom:girl_happy.png",
// catgirl_peek: "custom:catgirl_peek.png", hug_plushie: "custom:hug_plushie.png",
// girl_happy: "custom:girl_happy.png", huggies: "custom:huggies.png",
// hug_plushie: "custom:hug_plushie.png", noted: "custom:noted.gif",
// huggies: "custom:huggies.png", waving: "custom:waving.png",
// noted: "custom:noted.gif", mogusvented: "custom:mogusvented.png",
// waving: "custom:waving.png", },
// mogusvented: "custom:mogusvented.png",
// },
}; };

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/ban-ts-comment */
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { Channel, User, Role } from "revolt.js"; import { Channel, User } from "revolt.js";
import { Emoji as CustomEmoji } from "revolt.js/esm/maps/Emojis"; import { Emoji as CustomEmoji } from "revolt.js/esm/maps/Emojis";
import styled, { css } from "styled-components/macro"; import styled, { css } from "styled-components/macro";
@@ -29,16 +29,11 @@ export type AutoCompleteState =
type: "channel"; type: "channel";
matches: Channel[]; matches: Channel[];
} }
| {
type: "role";
matches: Role[];
}
)); ));
export type SearchClues = { export type SearchClues = {
users?: { type: "channel"; id: string } | { type: "all" }; users?: { type: "channel"; id: string } | { type: "all" };
channels?: { server: string }; channels?: { server: string };
roles?: { server: string };
}; };
export type AutoCompleteProps = { export type AutoCompleteProps = {
@@ -64,7 +59,7 @@ export function useAutoComplete(
function findSearchString( function findSearchString(
el: HTMLTextAreaElement, el: HTMLTextAreaElement,
): ["emoji" | "user" | "channel" | "role", string, number] | undefined { ): ["emoji" | "user" | "channel", string, number] | undefined {
if (el.selectionStart === el.selectionEnd) { if (el.selectionStart === el.selectionEnd) {
const cursor = el.selectionStart; const cursor = el.selectionStart;
const content = el.value.slice(0, cursor); const content = el.value.slice(0, cursor);
@@ -76,8 +71,6 @@ export function useAutoComplete(
return ["user", "", j]; return ["user", "", j];
} else if (content[j] === "#") { } else if (content[j] === "#") {
return ["channel", "", j]; return ["channel", "", j];
} else if (content[j] === "%") {
return ["role", "", j];
} }
while (j >= 0 && valid.test(content[j])) { while (j >= 0 && valid.test(content[j])) {
@@ -87,12 +80,7 @@ export function useAutoComplete(
if (j === -1) return; if (j === -1) return;
const current = content[j]; const current = content[j];
if ( if (current === ":" || current === "@" || current === "#") {
current === ":" ||
current === "@" ||
current === "#" ||
current === "%"
) {
const search = content.slice(j + 1, content.length); const search = content.slice(j + 1, content.length);
const minLen = current === ":" ? 2 : 1; const minLen = current === ":" ? 2 : 1;
@@ -102,8 +90,6 @@ export function useAutoComplete(
? "channel" ? "channel"
: current === ":" : current === ":"
? "emoji" ? "emoji"
: current === "%"
? "role"
: "user", : "user",
search.toLowerCase(), search.toLowerCase(),
current === ":" ? j + 1 : j, current === ":" ? j + 1 : j,
@@ -244,42 +230,6 @@ export function useAutoComplete(
return; return;
} }
} }
if (type === "role" && searchClues?.roles) {
const server = client.servers.get(searchClues.roles.server);
let roles: (Role & { id: string })[] = [];
if (server?.roles) {
roles = Object.entries(server.roles).map(([id, role]) => ({
...role,
id,
}));
}
const matches = (
search.length > 0
? roles.filter((role) =>
role.name.toLowerCase().match(regex),
)
: roles
)
.splice(0, 5)
.filter((x) => typeof x !== "undefined");
if (matches.length > 0) {
const currentPosition =
state.type !== "none" ? state.selected : 0;
setState({
type: "role",
matches,
selected: Math.min(currentPosition, matches.length - 1),
within: false,
});
return;
}
}
} }
if (state.type !== "none") { if (state.type !== "none") {
@@ -312,14 +262,6 @@ export function useAutoComplete(
state.matches[state.selected]._id, state.matches[state.selected]._id,
"> ", "> ",
); );
} else if (state.type === "role") {
content.splice(
index,
search.length + 1,
"<%",
state.matches[state.selected].id,
"> ",
);
} else { } else {
content.splice( content.splice(
index, index,
@@ -550,7 +492,7 @@ export default function AutoComplete({
{state.type === "user" && {state.type === "user" &&
state.matches.map((match, i) => ( state.matches.map((match, i) => (
<button <button
key={match._id} key={match}
className={i === state.selected ? "active" : ""} className={i === state.selected ? "active" : ""}
onMouseEnter={() => onMouseEnter={() =>
(i !== state.selected || !state.within) && (i !== state.selected || !state.within) &&
@@ -575,7 +517,7 @@ export default function AutoComplete({
{state.type === "channel" && {state.type === "channel" &&
state.matches.map((match, i) => ( state.matches.map((match, i) => (
<button <button
key={match._id} key={match}
className={i === state.selected ? "active" : ""} className={i === state.selected ? "active" : ""}
onMouseEnter={() => onMouseEnter={() =>
(i !== state.selected || !state.within) && (i !== state.selected || !state.within) &&
@@ -597,40 +539,6 @@ export default function AutoComplete({
{match.name} {match.name}
</button> </button>
))} ))}
{state.type === "role" &&
state.matches.map((match, i) => (
<button
key={match._id}
className={i === state.selected ? "active" : ""}
onMouseEnter={() =>
(i !== state.selected || !state.within) &&
setState({
...state,
selected: i,
within: true,
})
}
onMouseLeave={() =>
state.within &&
setState({
...state,
within: false,
})
}
onClick={onClick}>
<div
style={{
width: "16px",
height: "16px",
borderRadius: "50%",
backgroundColor: match.colour || "#7c7c7c",
marginRight: "8px",
flexShrink: 0,
}}
/>
{match.name}
</button>
))}
</div> </div>
</Base> </Base>
); );

View File

@@ -43,11 +43,11 @@ function toCodePoint(rune: string) {
} }
export function parseEmoji(emoji: string) { export function parseEmoji(emoji: string) {
// if (emoji.startsWith("custom:")) { if (emoji.startsWith("custom:")) {
// return `https://dl.insrt.uk/projects/revolt/emotes/${emoji.substring( return `https://dl.insrt.uk/projects/revolt/emotes/${emoji.substring(
// 7, 7,
// )}`; )}`;
// } }
const codepoint = toCodePoint(emoji); const codepoint = toCodePoint(emoji);
return `https://static.revolt.chat/emoji/${EMOJI_PACK}/${codepoint}.svg?rev=${REVISION}`; return `https://static.revolt.chat/emoji/${EMOJI_PACK}/${codepoint}.svg?rev=${REVISION}`;

View File

@@ -305,7 +305,7 @@ export default observer(({ channel }: Props) => {
if (!state.draft.has(channel._id)) { if (!state.draft.has(channel._id)) {
setMessage(text); setMessage(text);
} else { } else {
setMessage(`${state.draft.get(channel._id)?.content}\n${text}`); setMessage(`${state.draft.get(channel._id)}\n${text}`);
} }
} }
@@ -324,7 +324,7 @@ export default observer(({ channel }: Props) => {
return; return;
const content = state.draft.get(channel._id)?.content?.trim() ?? ""; const content = state.draft.get(channel._id)?.content?.trim() ?? "";
if (uploadState.type !== "none") return sendFile(content); if (uploadState.type === "attached") return sendFile(content);
if (content.length === 0) return; if (content.length === 0) return;
internalEmit("NewMessages", "hide"); internalEmit("NewMessages", "hide");
@@ -406,9 +406,7 @@ export default observer(({ channel }: Props) => {
* @returns * @returns
*/ */
async function sendFile(content: string) { async function sendFile(content: string) {
if (uploadState.type !== "attached" && uploadState.type !== "failed") if (uploadState.type !== "attached") return;
return;
const attachments: string[] = []; const attachments: string[] = [];
setMessage; setMessage;
@@ -567,7 +565,6 @@ export default observer(({ channel }: Props) => {
channel.channel_type === "TextChannel" channel.channel_type === "TextChannel"
? { server: channel.server_id! } ? { server: channel.server_id! }
: undefined, : undefined,
roles: { server: channel.server_id! },
}); });
return ( return (

View File

@@ -27,7 +27,7 @@ export default function AttachmentActions({ attachment }: Props) {
const url = client.generateFileURL(attachment); const url = client.generateFileURL(attachment);
const open_url = `${url}/${filename}`; const open_url = `${url}/${filename}`;
const download_url = url; const download_url = url?.replace("attachments", "attachments/download");
const filesize = determineFileSize(size); const filesize = determineFileSize(size);
@@ -49,11 +49,10 @@ export default function AttachmentActions({ attachment }: Props) {
</IconButton> </IconButton>
</a> </a>
<a <a
target="_blank"
href={download_url} href={download_url}
className={styles.downloadIcon} className={styles.downloadIcon}
download download
// target={isFirefox || window.native ? "_blank" : "_self"} target={isFirefox || window.native ? "_blank" : "_self"}
rel="noreferrer"> rel="noreferrer">
<IconButton> <IconButton>
<Download size={24} /> <Download size={24} />

View File

@@ -119,7 +119,7 @@ export default function UserBadges({ badges, uid }: Props) {
}} }}
onClick={() => { onClick={() => {
window.open( window.open(
"https://wiki.revolt.chat/notes/project/financial-support/", "https://insrt.uk/donate",
"_blank", "_blank",
); );
}} }}

View File

@@ -185,8 +185,7 @@ const Container = styled.div<{ largeEmoji: boolean }>`
/** /**
* Regex for matching execessive recursion of blockquotes and lists * Regex for matching execessive recursion of blockquotes and lists
*/ */
const RE_RECURSIVE = const RE_RECURSIVE = /(^(?:[>*+-][^\S\r\n]*){5})(?:[>*+-][^\S\r\n]*)+(.*$)/gm;
/(^(?:(?:[>*+-]|\d+\.)[^\S\r\n]*){5})(?:(?:[>*+-]|\d+\.)[^\S\r\n]*)+(.*$)/gm;
/** /**
* Regex for matching multi-line blockquotes * Regex for matching multi-line blockquotes
@@ -248,13 +247,9 @@ export default memo(({ content, disallowBigEmoji }: MarkdownProps) => {
const [Content, setContent] = useState<React.ReactElement>(null!); const [Content, setContent] = useState<React.ReactElement>(null!);
useLayoutEffect(() => { useLayoutEffect(() => {
try {
render render
.process(sanitisedContent) .process(sanitisedContent)
.then((file) => setContent(file.result)); .then((file) => setContent(file.result));
} catch (err) {
setContent("Message failed to render." as never);
}
}, [sanitisedContent]); }, [sanitisedContent]);
const largeEmoji = useMemo( const largeEmoji = useMemo(

View File

@@ -39,7 +39,7 @@ export default function AccountManagement() {
<CategoryButton <CategoryButton
icon={<Block size={24} color="var(--error)" />} icon={<Block size={24} color="var(--error)" />}
description={ description={
<Text id="app.settings.pages.account.manage.disable_description" /> "Disable your account. You won't be able to access it unless you contact support."
} }
action="chevron" action="chevron"
onClick={callback("disable")}> onClick={callback("disable")}>
@@ -49,7 +49,7 @@ export default function AccountManagement() {
<CategoryButton <CategoryButton
icon={<Trash size={24} color="var(--error)" />} icon={<Trash size={24} color="var(--error)" />}
description={ description={
<Text id="app.settings.pages.account.manage.delete_description" /> "Your account will be queued for deletion, a confirmation email will be sent."
} }
action="chevron" action="chevron"
onClick={callback("delete")}> onClick={callback("delete")}>

View File

@@ -159,7 +159,7 @@ class ClientController {
}) })
.catch((err) => { .catch((err) => {
const error = takeError(err); const error = takeError(err);
if (error === "Unauthorized") { if (error === "Forbidden" || error === "Unauthorized") {
this.sessions.delete(user_id); this.sessions.delete(user_id);
this.current = null; this.current = null;
this.pickNextSession(); this.pickNextSession();

View File

@@ -10,9 +10,8 @@ export function takeError(error: any): string {
case 429: case 429:
return "TooManyRequests"; return "TooManyRequests";
case 401: case 401:
return "Unauthorized"
case 403: case 403:
return "Forbidden"; return "Unauthorized";
default: default:
return "UnknownError"; return "UnknownError";
} }

View File

@@ -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 { clientController, useClient } from "../../ClientController"; import { useClient } from "../../ClientController";
import { takeError } from "../error"; import { takeError } from "../error";
type BehaviourType = type BehaviourType =
@@ -67,16 +67,9 @@ 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,
}); });

View File

@@ -297,5 +297,4 @@ export const modalController = new ModalControllerExtended({
report_success: ReportSuccess, report_success: ReportSuccess,
modify_displayname: ModifyDisplayname, modify_displayname: ModifyDisplayname,
changelog_usernames: ChangelogUsernames, changelog_usernames: ChangelogUsernames,
reset_bot_token: Confirmation
}); });

View File

@@ -20,7 +20,6 @@ export default function Confirmation(
| "delete_bot" | "delete_bot"
| "block_user" | "block_user"
| "unfriend_user" | "unfriend_user"
| "reset_bot_token"
>, >,
) { ) {
const history = useHistory(); const history = useHistory();
@@ -32,7 +31,6 @@ export default function Confirmation(
delete_bot: ["confirm_delete", "delete"], delete_bot: ["confirm_delete", "delete"],
unfriend_user: ["unfriend_user", "remove"], unfriend_user: ["unfriend_user", "remove"],
block_user: ["block_user", "block"], block_user: ["block_user", "block"],
reset_bot_token: ["reset_bot_token", "reset"],
}; };
const event = EVENTS[props.type]; const event = EVENTS[props.type];
@@ -90,12 +88,6 @@ export default function Confirmation(
.bots.delete(props.target); .bots.delete(props.target);
props.cb?.(); props.cb?.();
break; break;
case "reset_bot_token":
clientController
.getAvailableClient()
.bots
.edit(props.target.id, { remove: ["Token"] })
.then(props.callback)
} }
}} }}
submit={{ submit={{

View File

@@ -5,7 +5,6 @@ import { Text } from "preact-i18n";
import { Column, H1, IconButton, Modal, Row } from "@revoltchat/ui"; import { Column, H1, IconButton, Modal, Row } from "@revoltchat/ui";
import Markdown from "../../../components/markdown/Markdown"; import Markdown from "../../../components/markdown/Markdown";
import { useClient } from "../../client/ClientController";
import { report } from "../../safety"; import { report } from "../../safety";
import { modalController } from "../ModalController"; import { modalController } from "../ModalController";
import { ModalProps } from "../types"; import { ModalProps } from "../types";
@@ -14,49 +13,6 @@ export default function ServerInfo({
server, server,
...props ...props
}: ModalProps<"server_info">) { }: ModalProps<"server_info">) {
const client = useClient();
const isOwner = server.owner === client.user?._id;
const actions = [
{
onClick: () => {
modalController.push({
type: "server_identity",
member: server.member!,
});
return true;
},
children: "Edit Identity",
palette: "primary",
},
];
if (!isOwner) {
actions.push({
onClick: () => {
modalController.push({
type: "leave_server",
target: server,
});
return true;
},
children: "Leave Server",
palette: "error",
});
}
actions.push({
onClick: () => {
modalController.push({
type: "report",
target: server,
});
return true;
},
children: <Text id="app.special.modals.actions.report" />,
palette: "error",
});
return ( return (
<Modal <Modal
{...props} {...props}
@@ -70,7 +26,30 @@ export default function ServerInfo({
</IconButton> </IconButton>
</Row> </Row>
} }
actions={actions}> actions={[
{
onClick: () => {
modalController.push({
type: "server_identity",
member: server.member!,
});
return true;
},
children: "Edit Identity",
palette: "primary",
},
{
onClick: () => {
modalController.push({
type: "report",
target: server,
});
return true;
},
children: <Text id="app.special.modals.actions.report" />,
palette: "error",
},
]}>
<Markdown content={server.description!} /> <Markdown content={server.description!} />
</Modal> </Modal>
); );

View File

@@ -6,7 +6,6 @@ import {
UserX, UserX,
Group, Group,
InfoCircle, InfoCircle,
Flag,
} from "@styled-icons/boxicons-solid"; } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { Link, useHistory } from "react-router-dom"; import { Link, useHistory } from "react-router-dom";
@@ -247,24 +246,6 @@ export const UserProfile = observer(
<UserX size={28} /> <UserX size={28} />
</IconButton> </IconButton>
)} )}
{!user.bot && flags != 2 && flags != 4 && (
<Localizer>
<Tooltip
content={
<Text id="app.context_menu.report_user" />
}>
<IconButton
onClick={() =>
modalController.push({
type: "report",
target: user,
})
}>
<Flag size={28} />
</IconButton>
</Tooltip>
</Localizer>
)}
</div> </div>
{badges > 0 && ( {badges > 0 && (
<div <div

View File

@@ -190,11 +190,6 @@ export type Modal = {
type: "report_success"; type: "report_success";
user?: User; user?: User;
} }
| {
type: "reset_bot_token";
target: { name: string, id: string },
callback: () => Promise<void>;
}
); );
export type ModalProps<T extends Modal["type"]> = Modal & { type: T } & { export type ModalProps<T extends Modal["type"]> = Modal & { type: T } & {

View File

@@ -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;
@@ -51,7 +53,6 @@ interface ContextMenuData {
type Action = type Action =
| { action: "copy_id"; id: string } | { action: "copy_id"; id: string }
| { action: "admin"; id: string; type: "channel" | "message" | "user" } | { action: "admin"; id: string; type: "channel" | "message" | "user" }
| { action: "admin_system"; id: string }
| { action: "copy_message_link"; message: Message } | { action: "copy_message_link"; message: Message }
| { action: "copy_selection" } | { action: "copy_selection" }
| { action: "copy_text"; content: string } | { action: "copy_text"; content: string }
@@ -139,12 +140,6 @@ export default function ContextMenus() {
"_blank", "_blank",
); );
break; break;
case "admin_system":
window.open(
`https://admin.revolt.chat/panel/inspect/user/${data.id}`,
"_blank",
);
break;
case "copy_message_link": case "copy_message_link":
{ {
let pathname = `/channel/${data.message.channel_id}/${data.message._id}`; let pathname = `/channel/${data.message.channel_id}/${data.message._id}`;
@@ -288,7 +283,11 @@ export default function ContextMenus() {
window.open( window.open(
// ! FIXME: do this from revolt.js // ! FIXME: do this from revolt.js
client client
.generateFileURL(data.attachment), .generateFileURL(data.attachment)
?.replace(
"attachments",
"attachments/download",
),
isFirefox || window.native ? "_blank" : "_self", isFirefox || window.native ? "_blank" : "_self",
); );
} }
@@ -506,8 +505,6 @@ export default function ContextMenus() {
<span style={{ color }}> <span style={{ color }}>
{locale === "admin" ? ( {locale === "admin" ? (
"Open in Admin Panel" "Open in Admin Panel"
) : locale === "admin_system" ? (
"Open User in Admin Panel"
) : ( ) : (
<Text <Text
id={`app.context_menu.${ id={`app.context_menu.${
@@ -1134,22 +1131,6 @@ export default function ContextMenus() {
}, },
"admin", "admin",
); );
switch (message?.system?.type) {
case "user_added":
case "user_remove":
case "user_joined":
case "user_left":
case "user_kicked":
case "user_banned":
generateAction(
{
action: "admin_system",
id: message.system.id,
},
"admin_system",
);
}
} }
generateAction( generateAction(

View File

@@ -1,6 +1,5 @@
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";
@@ -164,7 +163,6 @@ 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!,
@@ -178,46 +176,6 @@ 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"

View File

@@ -34,7 +34,7 @@
a { a {
width: 100%; width: 100%;
height: 6em;
div { div {
margin: 0; margin: 0;
} }
@@ -54,4 +54,3 @@
[data-light="true"] .home svg { [data-light="true"] .home svg {
filter: invert(100%); filter: invert(100%);
} }

View File

@@ -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[] = [];
@@ -175,7 +175,7 @@ export default observer(() => {
</CategoryButton> </CategoryButton>
</Link> </Link>
<a <a
href="https://wiki.revolt.chat/notes/project/financial-support/" href="https://insrt.uk/donate"
target="_blank" target="_blank"
rel="noreferrer"> rel="noreferrer">
<CategoryButton <CategoryButton

View File

@@ -202,9 +202,11 @@ export const Form = observer(({ page, callback }: Props) => {
/> />
)} )}
{error && ( {error && (
<p style={{ fontSize: "0.8em", color: "var(--error)" }}> <Category>
<Text id={`error.${error}`} children={error} /> <I18nError error={error}>
</p> <Text id={`login.error.${page}`} />
</I18nError>
</Category>
)} )}
<Button> <Button>
<Text <Text
@@ -257,7 +259,7 @@ export const Form = observer(({ page, callback }: Props) => {
<span> <span>
<Text id="login.unofficial_instance" />{" "} <Text id="login.unofficial_instance" />{" "}
<a <a
href="https://developers.revolt.chat/faq.html" href="https://developers.revolt.chat/faq/instances#what-is-a-third-party-instance"
style={{ color: "var(--accent)" }} style={{ color: "var(--accent)" }}
target="_blank" target="_blank"
rel="noreferrer"> rel="noreferrer">

View File

@@ -281,7 +281,7 @@ export default observer(() => {
</ButtonItem> </ButtonItem>
</a> </a>
<a <a
href="https://wiki.revolt.chat/notes/project/financial-support/" href="https://insrt.uk/donate"
target="_blank" target="_blank"
rel="noreferrer"> rel="noreferrer">
<ButtonItem className={styles.donate} compact> <ButtonItem className={styles.donate} compact>

View File

@@ -35,7 +35,6 @@ import { modalController } from "../../../controllers/modals/ModalController";
interface Data { interface Data {
_id: string; _id: string;
token: string;
username: string; username: string;
public: boolean; public: boolean;
interactions_url?: string; interactions_url?: string;
@@ -75,7 +74,6 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
const [user, setUser] = useState<User>(client.users.get(bot._id)!); const [user, setUser] = useState<User>(client.users.get(bot._id)!);
const [data, setData] = useState<Data>({ const [data, setData] = useState<Data>({
_id: bot._id, _id: bot._id,
token: bot.token,
username: user.username, username: user.username,
public: bot.public, public: bot.public,
interactions_url: bot.interactions_url as any, interactions_url: bot.interactions_url as any,
@@ -96,7 +94,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
const refreshProfile = useCallback(() => { const refreshProfile = useCallback(() => {
client.api client.api
.get(`/users/${bot._id as ""}/profile`, undefined, { .get(`/users/${bot._id as ""}/profile`, undefined, {
headers: { "x-bot-token": data.token }, headers: { "x-bot-token": bot.token },
}) })
.then((profile) => setProfile(profile ?? {})); .then((profile) => setProfile(profile ?? {}));
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -151,7 +149,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
"/users/@me", "/users/@me",
avatar ? { avatar } : { remove: ["Avatar"] }, avatar ? { avatar } : { remove: ["Avatar"] },
{ {
headers: { "x-bot-token": data.token }, headers: { "x-bot-token": bot.token },
}, },
); );
@@ -170,7 +168,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
? { profile: { background } } ? { profile: { background } }
: { remove: ["ProfileBackground"] }, : { remove: ["ProfileBackground"] },
{ {
headers: { "x-bot-token": data.token }, headers: { "x-bot-token": bot.token },
}, },
); );
@@ -186,7 +184,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
"/users/@me", "/users/@me",
content ? { profile: { content } } : { remove: ["ProfileContent"] }, content ? { profile: { content } } : { remove: ["ProfileContent"] },
{ {
headers: { "x-bot-token": data.token }, headers: { "x-bot-token": bot.token },
}, },
); );
@@ -314,7 +312,6 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
if (editMode) { if (editMode) {
setData({ setData({
_id: bot._id, _id: bot._id,
token: data.token,
username: user!.username, username: user!.username,
public: bot.public, public: bot.public,
interactions_url: bot.interactions_url as any, interactions_url: bot.interactions_url as any,
@@ -337,7 +334,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
<CategoryButton <CategoryButton
account account
icon={<Key size={24} />} icon={<Key size={24} />}
onClick={() => modalController.writeText(data.token)} onClick={() => modalController.writeText(bot.token)}
description={ description={
<> <>
{"••••• "} {"••••• "}
@@ -347,7 +344,7 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
ev, ev,
modalController.push({ modalController.push({
type: "show_token", type: "show_token",
token: data.token, token: bot.token,
name: user!.username, name: user!.username,
}), }),
) )
@@ -493,25 +490,6 @@ function BotCard({ bot, onDelete, onUpdate }: Props) {
}> }>
<Text id="app.settings.pages.bots.add" /> <Text id="app.settings.pages.bots.add" />
</Button> </Button>
<Button
palette="error"
onClick={ async () => {
modalController.push({
type: "reset_bot_token",
target: { name: user.username, id: bot._id },
callback: async () => {
const updatedBot = await client.bots.fetch(bot._id);
setData({
...data,
token: updatedBot.bot.token
})
}
})
}
}>
<Text id="app.settings.pages.bots.reset_token" />
</Button>
</> </>
)} )}
</div> </div>

View File

@@ -144,7 +144,7 @@ export function Native() {
</Button> </Button>
</p> </p>
<h3 style={{ marginTop: "4em" }}>Local Development Mode</h3> <h3 style={{ marginTop: "4em" }}>Local Development Mode</h3>
{/*config.build === "dev" ? ( {config.build === "dev" ? (
<> <>
<h5>Development mode is currently on.</h5> <h5>Development mode is currently on.</h5>
<Button <Button
@@ -197,7 +197,7 @@ export function Native() {
</Button> </Button>
</p> </p>
</> </>
)*/} )}
<hr /> <hr />
<CategoryButton <CategoryButton
icon={<img src={RLogo} draggable={false} />} icon={<img src={RLogo} draggable={false} />}

View File

@@ -369,9 +369,7 @@ function ListElement({
<KanbanList last={false} key={category.id}> <KanbanList last={false} key={category.id}>
<div className="inner"> <div className="inner">
<Row> <Row>
<KanbanListHeader <KanbanListHeader {...provided.dragHandleProps}>
{...provided.dragHandleProps}
onClick={startEditing}>
{editing !== undefined ? ( {editing !== undefined ? (
<input <input
value={editing} value={editing}
@@ -386,7 +384,7 @@ function ListElement({
id={category.id} id={category.id}
/> />
) : ( ) : (
<span> <span onClick={startEditing}>
{category.title} {category.title}
</span> </span>
)} )}

View File

@@ -103,43 +103,10 @@ export const Members = ({ server }: Props) => {
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
useEffect(() => { useEffect(() => {
function fetch() {
server server
.fetchMembers() .fetchMembers()
.then((data) => data.members) .then((data) => data.members)
.then(setData); .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(

View File

@@ -14,7 +14,6 @@
"isolatedModules": true, "isolatedModules": true,
"noEmit": true, "noEmit": true,
"jsx": "preserve", "jsx": "preserve",
"jsxImportSource": "preact",
"jsxFactory": "h", "jsxFactory": "h",
"jsxFragmentFactory": "Fragment", "jsxFragmentFactory": "Fragment",
"types": ["vite-plugin-pwa/client"], "types": ["vite-plugin-pwa/client"],