mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-25 08:30:58 -05:00
Use loading="lazy" in more places.
i18n invites page. Polish the bans page.
This commit is contained in:
parent
ca975aae7b
commit
dbaf246c27
15 changed files with 142 additions and 41 deletions
2
external/lang
vendored
2
external/lang
vendored
|
@ -1 +1 @@
|
|||
Subproject commit b70b4f395caf4dc4911c5ccbf7188de198875173
|
||||
Subproject commit b40f8ce53831a590c0ffdd02f8da9fd35b7a3701
|
|
@ -67,6 +67,7 @@ export default function AgeGate(props: Props) {
|
|||
return (
|
||||
<Base>
|
||||
<img
|
||||
loading="eager"
|
||||
src={"https://static.revolt.chat/emoji/mutant/26a0.svg"}
|
||||
draggable={false}
|
||||
/>
|
||||
|
|
|
@ -55,6 +55,7 @@ export default function Emoji({
|
|||
return (
|
||||
<img
|
||||
alt={emoji}
|
||||
loading="lazy"
|
||||
className="emoji"
|
||||
draggable={false}
|
||||
src={parseEmoji(emoji)}
|
||||
|
@ -66,7 +67,7 @@ export default function Emoji({
|
|||
}
|
||||
|
||||
export function generateEmoji(emoji: string) {
|
||||
return `<img class="emoji" draggable="false" alt="${emoji}" src="${parseEmoji(
|
||||
return `<img loading="lazy" class="emoji" draggable="false" alt="${emoji}" src="${parseEmoji(
|
||||
emoji,
|
||||
)}" />`;
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ function FileEntry({
|
|||
return (
|
||||
<Entry className={index >= CAN_UPLOAD_AT_ONCE ? "fade" : ""}>
|
||||
<PreviewBox onClick={remove}>
|
||||
<img class="icon" src={url} alt={file.name} />
|
||||
<img class="icon" src={url} alt={file.name} loading="eager" />
|
||||
<div class="overlay">
|
||||
<XCircle size={36} />
|
||||
</div>
|
||||
|
|
|
@ -97,6 +97,7 @@ export function TypingIndicator({ typing }: Props) {
|
|||
<div className="avatars">
|
||||
{users.map((user) => (
|
||||
<img
|
||||
loading="eager"
|
||||
src={client.users.getAvatarURL(
|
||||
user._id,
|
||||
{ max_side: 256 },
|
||||
|
|
|
@ -91,6 +91,7 @@ export default function Embed({ embed }: Props) {
|
|||
<div className={styles.siteinfo}>
|
||||
{embed.icon_url && (
|
||||
<img
|
||||
loading="lazy"
|
||||
className={styles.favicon}
|
||||
src={client.proxyFile(embed.icon_url)}
|
||||
draggable={false}
|
||||
|
|
|
@ -143,7 +143,9 @@ function HomeSidebar(props: Props) {
|
|||
})
|
||||
}
|
||||
/>
|
||||
{channelsArr.length === 0 && <img src={placeholderSVG} />}
|
||||
{channelsArr.length === 0 && (
|
||||
<img src={placeholderSVG} loading="eager" />
|
||||
)}
|
||||
{channelsArr.map((x) => {
|
||||
let user;
|
||||
if (x.channel_type === "DirectMessage") {
|
||||
|
|
|
@ -144,7 +144,9 @@ export function GroupMemberSidebar({
|
|||
}
|
||||
/>
|
||||
}>
|
||||
{members.length === 0 && <img src={placeholderSVG} />}
|
||||
{members.length === 0 && (
|
||||
<img src={placeholderSVG} loading="eager" />
|
||||
)}
|
||||
{members.map(
|
||||
(user) =>
|
||||
user && (
|
||||
|
@ -257,7 +259,9 @@ export function ServerMemberSidebar({
|
|||
{users.length}
|
||||
</span>
|
||||
}>
|
||||
{users.length === 0 && <img src={placeholderSVG} />}
|
||||
{users.length === 0 && (
|
||||
<img src={placeholderSVG} loading="eager" />
|
||||
)}
|
||||
{users.map(
|
||||
(user) =>
|
||||
user && (
|
||||
|
|
|
@ -40,7 +40,7 @@ export function OnboardingModal({ onClose, callback }: Props) {
|
|||
<div className={styles.header}>
|
||||
<h1>
|
||||
<Text id="app.special.modals.onboarding.welcome" />
|
||||
<img src={wideSVG} />
|
||||
<img src={wideSVG} loading="eager" />
|
||||
</h1>
|
||||
</div>
|
||||
<div className={styles.form}>
|
||||
|
|
|
@ -37,6 +37,7 @@ export function ImageViewer({ attachment, embed, onClose }: Props) {
|
|||
{attachment && (
|
||||
<>
|
||||
<img
|
||||
loading="eager"
|
||||
src={client.generateFileURL(attachment)}
|
||||
width={(attachment.metadata as ImageMetadata).width}
|
||||
height={
|
||||
|
@ -49,6 +50,7 @@ export function ImageViewer({ attachment, embed, onClose }: Props) {
|
|||
{embed && (
|
||||
<>
|
||||
<img
|
||||
loading="eager"
|
||||
src={client.proxyFile(embed.url)}
|
||||
width={embed.width}
|
||||
height={embed.height}
|
||||
|
|
|
@ -3,10 +3,9 @@ import { Client, PermissionCalculator } from "revolt.js";
|
|||
import { Channels, Servers, Users } from "revolt.js/dist/api/objects";
|
||||
import Collection from "revolt.js/dist/maps/Collection";
|
||||
|
||||
import { useCallback, useContext, useEffect, useState } from "preact/hooks";
|
||||
import { useContext, useEffect, useState } from "preact/hooks";
|
||||
|
||||
//#region Hooks v1
|
||||
// ! Hooks v1 will be deprecated soon.
|
||||
import { AppContext } from "./RevoltClient";
|
||||
|
||||
export interface HookContext {
|
||||
|
|
|
@ -97,6 +97,7 @@ export function Component(props: Props) {
|
|||
<div className={styles.themes}>
|
||||
<div className={styles.theme}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={lightSVG}
|
||||
draggable={false}
|
||||
data-active={selected === "light"}
|
||||
|
@ -104,7 +105,7 @@ export function Component(props: Props) {
|
|||
selected !== "light" &&
|
||||
setTheme({ preset: "light" })
|
||||
}
|
||||
onContextMenu={e => e.preventDefault()}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
<h4>
|
||||
<Text id="app.settings.pages.appearance.color.light" />
|
||||
|
@ -112,13 +113,14 @@ export function Component(props: Props) {
|
|||
</div>
|
||||
<div className={styles.theme}>
|
||||
<img
|
||||
loading="eager"
|
||||
src={darkSVG}
|
||||
draggable={false}
|
||||
data-active={selected === "dark"}
|
||||
onClick={() =>
|
||||
selected !== "dark" && setTheme({ preset: "dark" })
|
||||
}
|
||||
onContextMenu={e => e.preventDefault()}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
<h4>
|
||||
<Text id="app.settings.pages.appearance.color.dark" />
|
||||
|
@ -202,7 +204,12 @@ export function Component(props: Props) {
|
|||
className={styles.button}
|
||||
onClick={() => setEmojiPack("mutant")}
|
||||
data-active={emojiPack === "mutant"}>
|
||||
<img src={mutantSVG} draggable={false} onContextMenu={e => e.preventDefault()} />
|
||||
<img
|
||||
loading="eager"
|
||||
src={mutantSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>
|
||||
Mutant Remix{" "}
|
||||
|
@ -219,7 +226,12 @@ export function Component(props: Props) {
|
|||
className={styles.button}
|
||||
onClick={() => setEmojiPack("twemoji")}
|
||||
data-active={emojiPack === "twemoji"}>
|
||||
<img src={twemojiSVG} draggable={false} onContextMenu={e => e.preventDefault()} />
|
||||
<img
|
||||
loading="eager"
|
||||
src={twemojiSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>Twemoji</h4>
|
||||
</div>
|
||||
|
@ -230,7 +242,12 @@ export function Component(props: Props) {
|
|||
className={styles.button}
|
||||
onClick={() => setEmojiPack("openmoji")}
|
||||
data-active={emojiPack === "openmoji"}>
|
||||
<img src={openmojiSVG} draggable={false} onContextMenu={e => e.preventDefault()} />
|
||||
<img
|
||||
loading="eager"
|
||||
src={openmojiSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>Openmoji</h4>
|
||||
</div>
|
||||
|
@ -239,7 +256,12 @@ export function Component(props: Props) {
|
|||
className={styles.button}
|
||||
onClick={() => setEmojiPack("noto")}
|
||||
data-active={emojiPack === "noto"}>
|
||||
<img src={notoSVG} draggable={false} onContextMenu={e => e.preventDefault()} />
|
||||
<img
|
||||
loading="eager"
|
||||
src={notoSVG}
|
||||
draggable={false}
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
/>
|
||||
</div>
|
||||
<h4>Noto Emoji</h4>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import { Servers } from "revolt.js/dist/api/objects";
|
||||
import { XCircle } from "@styled-icons/boxicons-regular";
|
||||
import { Servers, Users } from "revolt.js/dist/api/objects";
|
||||
|
||||
import styles from "./Panes.module.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
import { useContext, useEffect, useState } from "preact/hooks";
|
||||
|
||||
import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
||||
|
||||
import Tip from "../../../components/ui/Tip";
|
||||
import UserIcon from "../../../components/common/user/UserIcon";
|
||||
import IconButton from "../../../components/ui/IconButton";
|
||||
import Preloader from "../../../components/ui/Preloader";
|
||||
|
||||
interface Props {
|
||||
server: Servers.Server;
|
||||
|
@ -12,26 +17,71 @@ interface Props {
|
|||
|
||||
export function Bans({ server }: Props) {
|
||||
const client = useContext(AppContext);
|
||||
const [bans, setBans] = useState<Servers.Ban[] | undefined>(undefined);
|
||||
const [deleting, setDelete] = useState<string[]>([]);
|
||||
const [data, setData] = useState<
|
||||
| {
|
||||
users: Pick<Users.User, "_id" | "username" | "avatar">[];
|
||||
bans: Servers.Ban[];
|
||||
}
|
||||
| undefined
|
||||
>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
client.servers.fetchBans(server._id).then((bans) => setBans(bans));
|
||||
client.servers.fetchBans(server._id).then(setData as any);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Tip warning>This section is under construction.</Tip>
|
||||
{bans?.map((x) => (
|
||||
<div>
|
||||
{x._id.user}: {x.reason ?? "no reason"}{" "}
|
||||
<button
|
||||
onClick={() =>
|
||||
client.servers.unbanUser(server._id, x._id.user)
|
||||
}>
|
||||
unban
|
||||
</button>
|
||||
<div className={styles.userList}>
|
||||
<div className={styles.subtitle}>
|
||||
<span>
|
||||
<Text id="app.settings.server_pages.bans.user" />
|
||||
</span>
|
||||
<span class={styles.reason}>
|
||||
<Text id="app.settings.server_pages.bans.reason" />
|
||||
</span>
|
||||
<span>
|
||||
<Text id="app.settings.server_pages.bans.revoke" />
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
{typeof data === "undefined" && <Preloader type="ring" />}
|
||||
{data?.bans.map((x) => {
|
||||
let user = data.users.find((y) => y._id === x._id.user);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.ban}
|
||||
data-deleting={deleting.indexOf(x._id.user) > -1}>
|
||||
<span>
|
||||
<UserIcon attachment={user?.avatar} size={24} />
|
||||
{user?.username}
|
||||
</span>
|
||||
<div className={styles.reason}>
|
||||
{x.reason ?? (
|
||||
<Text id="app.settings.server_pages.bans.no_reason" />
|
||||
)}
|
||||
</div>
|
||||
<IconButton
|
||||
onClick={async () => {
|
||||
setDelete([...deleting, x._id.user]);
|
||||
|
||||
await client.servers.unbanUser(
|
||||
server._id,
|
||||
x._id.user,
|
||||
);
|
||||
|
||||
setData({
|
||||
...data,
|
||||
bans: data.bans.filter(
|
||||
(y) => y._id.user !== x._id.user,
|
||||
),
|
||||
});
|
||||
}}
|
||||
disabled={deleting.indexOf(x._id.user) > -1}>
|
||||
<XCircle size={24} />
|
||||
</IconButton>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -37,12 +37,20 @@ export function Invites({ server }: Props) {
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div className={styles.invites}>
|
||||
<div className={styles.userList}>
|
||||
<div className={styles.subtitle}>
|
||||
<span>Invite Code</span>
|
||||
<span>Invitor</span>
|
||||
<span>Channel</span>
|
||||
<span>Revoke</span>
|
||||
<span>
|
||||
<Text id="app.settings.server_pages.invites.code" />
|
||||
</span>
|
||||
<span>
|
||||
<Text id="app.settings.server_pages.invites.invitor" />
|
||||
</span>
|
||||
<span>
|
||||
<Text id="app.settings.server_pages.invites.channel" />
|
||||
</span>
|
||||
<span>
|
||||
<Text id="app.settings.server_pages.invites.revoke" />
|
||||
</span>
|
||||
</div>
|
||||
{typeof invites === "undefined" && <Preloader type="ring" />}
|
||||
{invites?.map((invite) => {
|
||||
|
|
|
@ -17,21 +17,31 @@
|
|||
}
|
||||
}
|
||||
|
||||
.invites {
|
||||
.userList {
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.subtitle {
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
color: var(--secondary-foreground);
|
||||
font-weight: 700;
|
||||
|
||||
.reason {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.invite {
|
||||
.reason {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.invite,
|
||||
.ban {
|
||||
gap: 8px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
|
@ -39,8 +49,8 @@
|
|||
flex-direction: row;
|
||||
background: var(--secondary-background);
|
||||
|
||||
code,
|
||||
span {
|
||||
span,
|
||||
code {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue