This commit is contained in:
TaiAurori
2021-08-30 18:24:35 -04:00
32 changed files with 544 additions and 205 deletions

View File

@@ -6,6 +6,7 @@ import { decodeTime } from "ulid";
import { Text } from "preact-i18n";
import { useDictionary } from "../../../lib/i18n";
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
import { dayjs } from "../../../context/Locale";
@@ -34,9 +35,11 @@ export default styled.div<BaseMessageProps>`
flex-direction: row;
padding-inline-end: 16px;
@media (pointer: coarse) {
user-select: none;
}
${() =>
isTouchscreenDevice &&
css`
user-select: none;
`}
${(props) =>
props.contrast &&

View File

@@ -3,7 +3,7 @@ import Axios, { CancelTokenSource } from "axios";
import { observer } from "mobx-react-lite";
import { ChannelPermission } from "revolt.js/dist/api/permissions";
import { Channel } from "revolt.js/dist/maps/Channels";
import styled from "styled-components";
import styled, { css } from "styled-components";
import { ulid } from "ulid";
import { Text } from "preact-i18n";
@@ -99,11 +99,13 @@ const Action = styled.div`
padding: 12px;
}
.mobile {
@media (pointer: fine) {
display: none;
}
}
${() =>
!isTouchscreenDevice &&
css`
.mobile {
display: none;
}
`}
`;
// For sed replacement
@@ -316,7 +318,8 @@ export default observer(({ channel }: Props) => {
);
}
} catch (err) {
if (err?.message === "cancel") {
// eslint-disable-next-line
if ((err as any)?.message === "cancel") {
setUploadState({
type: "attached",
files,
@@ -502,6 +505,11 @@ export default observer(({ channel }: Props) => {
value={draft ?? ""}
padding="var(--message-box-padding)"
onKeyDown={(e) => {
if (e.ctrlKey && e.key === "Enter") {
e.preventDefault();
return send();
}
if (onKeyDown(e)) return;
if (

View File

@@ -1,10 +1,11 @@
import { DownArrowAlt } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { Channel } from "revolt.js/dist/maps/Channels";
import styled from "styled-components";
import styled, { css } from "styled-components";
import { Text } from "preact-i18n";
import { isTouchscreenDevice } from "../../../../lib/isTouchscreenDevice";
import { getRenderer } from "../../../../lib/renderer/Singleton";
const Bar = styled.div`
@@ -42,11 +43,13 @@ const Bar = styled.div`
transform: translateY(1px);
}
@media (pointer: coarse) {
height: 34px;
top: -32px;
padding: 0 12px;
}
${() =>
isTouchscreenDevice &&
css`
height: 34px;
top: -32px;
padding: 0 12px;
`}
}
`;

View File

@@ -24,6 +24,7 @@ import { generateEmoji } from "../common/Emoji";
import { emojiDictionary } from "../../assets/emojis";
import { MarkdownProps } from "./Markdown";
import {useIntermediate} from "../../context/intermediate/Intermediate";
// TODO: global.d.ts file for defining globals
declare global {
@@ -97,6 +98,8 @@ const RE_CHANNELS = /<#([A-z0-9]{26})>/g;
export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
const client = useContext(AppContext);
const { openScreen } = useIntermediate();
if (typeof content === "undefined") return null;
if (content.length === 0) return null;
@@ -198,6 +201,13 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
if (!internal) {
element.setAttribute("target", "_blank");
element.onclick = (ev) => {
ev.preventDefault();
openScreen({
id: "external_link_prompt",
link: href
})
}
}
},
);

View File

@@ -240,15 +240,18 @@ export const ServerListSidebar = observer(({ unreads, lastOpened }: Props) => {
let homeUnread: "mention" | "unread" | undefined;
let alertCount = 0;
for (const x of channels) {
if (
(x.channel?.channel_type === "DirectMessage"
? x.channel?.active
: x.channel?.channel_type === "Group") &&
x.unread
) {
if (x.channel?.channel_type === "Group" && x.unread) {
homeUnread = "unread";
alertCount += x.alertCount ?? 0;
}
if (
x.channel?.channel_type === "DirectMessage" &&
x.channel.active &&
x.unread
) {
alertCount++;
}
}
alertCount += [...client.users.values()].filter(

View File

@@ -37,9 +37,11 @@ export default styled.div<Props>`
padding: 0 12px;
}*/
@media (pointer: coarse) {
height: 56px;
}
${() =>
isTouchscreenDevice &&
css`
height: 56px;
`}
${(props) =>
props.background &&

View File

@@ -27,25 +27,37 @@ export enum Language {
GERMAN = "de",
GREEK = "el",
SPANISH = "es",
ESTONIAN = "et",
FINNISH = "fi",
FILIPINO = "fil",
FRENCH = "fr",
IRISH = "ga",
HINDI = "hi",
CROATIAN = "hr",
HUNGARIAN = "hu",
INDONESIAN = "id",
ITALIAN = "it",
JAPANESE = "ja",
KOREAN = "ko",
LUXEMBOURGISH = "lb",
LITHUANIAN = "lt",
MACEDONIAN = "mk",
MALAY = "ms",
NORWEGIAN_BOKMAL = "nb_NO",
DUTCH = "nl",
POLISH = "pl",
PORTUGUESE_BRAZIL = "pt_BR",
ROMANIAN = "ro",
RUSSIAN = "ru",
SLOVAK = "sk",
SLOVENIAN = "sl",
SERBIAN = "sr",
SWEDISH = "sv",
TAMIL = "ta",
THAI = "th",
TURKISH = "tr",
UKRANIAN = "uk",
VIETNAMESE = "vi",
CHINESE_SIMPLIFIED = "zh_Hans",
TOKIPONA = "tokipona",
@@ -81,15 +93,23 @@ export const Languages: { [key in Language]: LanguageEntry } = {
de: { display: "Deutsch", emoji: "🇩🇪", i18n: "de" },
el: { display: "Ελληνικά", emoji: "🇬🇷", i18n: "el" },
es: { display: "Español", emoji: "🇪🇸", i18n: "es" },
et: { display: "eesti", emoji: "🇪🇪", i18n: "et" },
fi: { display: "suomi", emoji: "🇫🇮", i18n: "fi" },
fil: { display: "Pilipino", emoji: "🇵🇭", i18n: "fil", dayjs: "tl-ph" },
fr: { display: "Français", emoji: "🇫🇷", i18n: "fr" },
ga: { display: "Gaeilge", emoji: "🇮🇪", i18n: "ga" },
hi: { display: "हिन्दी", emoji: "🇮🇳", i18n: "hi" },
hr: { display: "Hrvatski", emoji: "🇭🇷", i18n: "hr" },
hu: { display: "Magyar", emoji: "🇭🇺", i18n: "hu" },
id: { display: "bahasa Indonesia", emoji: "🇮🇩", i18n: "id" },
it: { display: "Italiano", emoji: "🇮🇹", i18n: "it" },
ja: { display: "日本", emoji: "🇯🇵", i18n: "ja" },
ko: { display: "한국어", emoji: "🇰🇷", i18n: "ko" },
lb: { display: "Lëtzebuergesch", emoji: "🇱🇺", i18n: "lb" },
lt: { display: "Lietuvių", emoji: "🇱🇹", i18n: "lt" },
mk: { display: "Македонски", emoji: "🇲🇰", i18n: "mk" },
ms: { display: "Melayu", emoji: "🇲🇾", i18n: "ms" },
nb_NO: { display: "Norsk bokmål", emoji: "🇳🇴", i18n: "nb_NO", dayjs: "nb" },
nl: { display: "Nederlands", emoji: "🇳🇱", i18n: "nl" },
pl: { display: "Polski", emoji: "🇵🇱", i18n: "pl" },
pt_BR: {
@@ -100,11 +120,15 @@ export const Languages: { [key in Language]: LanguageEntry } = {
},
ro: { display: "Română", emoji: "🇷🇴", i18n: "ro" },
ru: { display: "Русский", emoji: "🇷🇺", i18n: "ru" },
sk: { display: "Slovensky", emoji: "🇸🇰", i18n: "sk" },
sl: { display: "Slovenščina", emoji: "🇸🇮", i18n: "sl" },
sr: { display: "Српски", emoji: "🇷🇸", i18n: "sr" },
sv: { display: "Svenska", emoji: "🇸🇪", i18n: "sv" },
ta: { display: "தமிழ்", emoji: "🇱🇰", i18n: "ta" },
th: { display: "ไทย", emoji: "🇹🇭", i18n: "th" },
tr: { display: "Türkçe", emoji: "🇹🇷", i18n: "tr" },
uk: { display: "Українська", emoji: "🇺🇦", i18n: "uk" },
vi: { display: "Tiếng Việt", emoji: "🇻🇳", i18n: "vi" },
zh_Hans: {
display: "中文 (简体)",
emoji: "🇨🇳",

View File

@@ -24,6 +24,7 @@ export type Screen =
| { id: "signed_out" }
| { id: "error"; error: string }
| { id: "clipboard"; text: string }
| { id: "external_link_prompt"; link: string }
| {
id: "_prompt";
question: Children;
@@ -78,16 +79,16 @@ export type Screen =
}
// Pop-overs
| { id: "image_viewer"; attachment?: Attachment; embed?: EmbedImage }
| { id: "modify_account"; field: "username" | "email" | "password" }
| { id: "profile"; user_id: string }
| { id: "channel_info"; channel: Channel }
| { id: "pending_requests"; users: User[] }
| {
id: "user_picker";
omit?: string[];
callback: (users: string[]) => Promise<void>;
}
| { id: "image_viewer"; attachment?: Attachment; embed?: EmbedImage }
| { id: "channel_info"; channel: Channel }
| { id: "pending_requests"; users: User[] }
| { id: "modify_account"; field: "username" | "email" | "password" }
| {
id: "server_identity";
server: Server;

View File

@@ -9,6 +9,7 @@ import { InputModal } from "./modals/Input";
import { OnboardingModal } from "./modals/Onboarding";
import { PromptModal } from "./modals/Prompt";
import { SignedOutModal } from "./modals/SignedOut";
import {ExternalLinkModal} from "./modals/ExternalLinkPrompt";
export interface Props {
screen: Screen;
@@ -34,6 +35,8 @@ export default function Modals({ screen, openScreen }: Props) {
return <ClipboardModal onClose={onClose} {...screen} />;
case "onboarding":
return <OnboardingModal onClose={onClose} {...screen} />;
case "external_link_prompt":
return <ExternalLinkModal onClose={onClose} {...screen} />;
}
return null;

View File

@@ -26,22 +26,30 @@ export default function Popovers() {
switch (screen.id) {
case "profile":
// @ts-expect-error someone figure this out :)
return <UserProfile {...screen} onClose={onClose} />;
case "user_picker":
// @ts-expect-error someone figure this out :)
return <UserPicker {...screen} onClose={onClose} />;
case "image_viewer":
return <ImageViewer {...screen} onClose={onClose} />;
case "channel_info":
// @ts-expect-error someone figure this out :)
return <ChannelInfo {...screen} onClose={onClose} />;
case "pending_requests":
// @ts-expect-error someone figure this out :)
return <PendingRequests {...screen} onClose={onClose} />;
case "modify_account":
// @ts-expect-error someone figure this out :)
return <ModifyAccountModal onClose={onClose} {...screen} />;
case "special_prompt":
// @ts-expect-error someone figure this out :)
return <SpecialPromptModal onClose={onClose} {...screen} />;
case "special_input":
// @ts-expect-error someone figure this out :)
return <SpecialInputModal onClose={onClose} {...screen} />;
case "server_identity":
// @ts-expect-error someone figure this out :)
return <ServerIdentityModal onClose={onClose} {...screen} />;
}

View File

@@ -0,0 +1,37 @@
import { Text } from "preact-i18n";
import Modal from "../../../components/ui/Modal";
interface Props {
onClose: () => void;
link: string;
}
export function ExternalLinkModal({ onClose, link }: Props) {
return (
<Modal
visible={true}
onClose={onClose}
title={<Text id={"app.special.modals.external_links.title"} />}
actions={[
{
onClick: () => {
window.open(link, "_blank");
onClose();
},
confirmation: true,
contrast: true,
accent: true,
children: "Continue",
},
{
onClick: onClose,
confirmation: false,
children: "Cancel",
},
]}>
<Text id={"app.special.modals.external_links.short"} /> <br />
<a>{link}</a>
</Modal>
);
}

View File

@@ -55,7 +55,7 @@ export function OnboardingModal({ onClose, callback }: Props) {
onSubmit={
handleSubmit(
onSubmit,
) as JSX.GenericEventHandler<HTMLFormElement>
) as unknown as JSX.GenericEventHandler<HTMLFormElement>
}>
<div>
<FormField

View File

@@ -15,6 +15,7 @@ import { Children } from "../../types/Preact";
import { useIntermediate } from "../intermediate/Intermediate";
import { registerEvents, setReconnectDisallowed } from "./events";
import { takeError } from "./util";
import { Session } from "revolt-api/types/Auth";
export enum ClientStatus {
INIT,
@@ -79,7 +80,7 @@ function Context({ auth, children }: Props) {
const login = () =>
dispatch({
type: "LOGIN",
session: client.session!, // This [null assertion] is ok, we should have a session by now. - insert's words
session: client.session as Session,
});
if (onboarding) {

View File

@@ -99,7 +99,9 @@ export default function TextAreaAutoSize(props: TextAreaAutoSizeProps) {
// ? it is a quick and dirty hack to fix
// ? value not setting correctly
// ? I have no clue what's going on
ref.current.value = value;
// ref.current.value = value;
// * commented out of 30-08-21
// * hopefully nothing breaks :v
if (!autoFocus) return;
function keyDown(e: KeyboardEvent) {

View File

@@ -326,7 +326,8 @@ export default class VoiceClient extends EventEmitter<VoiceEvents> {
try {
await this.signaling.stopProduce(type);
} catch (error) {
if (error.error === WSErrorCode.ProducerNotFound) return;
// eslint-disable-next-line
if ((error as any).error === WSErrorCode.ProducerNotFound) return;
throw error;
}
}

View File

@@ -96,7 +96,7 @@ export default function MessageEditor({ message, finish }: Props) {
<AutoComplete detached {...autoCompleteProps} />
<TextAreaAutoSize
forceFocus
maxRows={3}
maxRows={10}
value={content}
maxLength={2000}
padding="var(--message-box-padding)"

View File

@@ -152,7 +152,7 @@ export function Form({ page, callback }: Props) {
onSubmit={
handleSubmit(
onSubmit,
) as JSX.GenericEventHandler<HTMLFormElement>
) as unknown as JSX.GenericEventHandler<HTMLFormElement>
}>
{page !== "reset" && (
<FormField

View File

@@ -16,10 +16,12 @@ function mapMailProvider(email?: string): [string, string] | undefined {
const domain = match[1];
switch (domain) {
case "gmail.com":
case "googlemail.com":
return ["Gmail", "https://gmail.com"];
case "tuta.io":
return ["Tutanota", "https://mail.tutanota.com"];
case "outlook.com":
case "hotmail.com":
return ["Outlook", "https://outlook.live.com"];
case "yahoo.com":
return ["Yahoo", "https://mail.yahoo.com"];
@@ -27,11 +29,24 @@ function mapMailProvider(email?: string): [string, string] | undefined {
return ["WP Poczta", "https://poczta.wp.pl"];
case "protonmail.com":
case "protonmail.ch":
case "pm.me":
return ["ProtonMail", "https://mail.protonmail.com"];
case "seznam.cz":
case "email.cz":
case "post.cz":
return ["Seznam", "https://email.seznam.cz"];
case "zoho.com":
return ["Zoho Mail", "https://mail.zoho.com/zm/"];
case "aol.com":
case "aim.com":
return ["AOL Mail", "https://mail.aol.com/"];
case "icloud.com":
return ["iCloud Mail", "https://mail.aol.com/"];
case "mail.com":
case "email.com":
return ["mail.com", "https://www.mail.com/mail/"];
case "yandex.com":
return ["Yandex Mail", "https://mail.yandex.com/"];
default:
return [domain, `https://${domain}`];
}

View File

@@ -1,3 +1,4 @@
import { observer } from "mobx-react-lite";
import { Profile as ProfileI } from "revolt-api/types/Users";
import styles from "./Panes.module.scss";
@@ -20,7 +21,7 @@ import AutoComplete, {
} from "../../../components/common/AutoComplete";
import Button from "../../../components/ui/Button";
export function Profile() {
export const Profile = observer(() => {
const status = useContext(StatusContext);
const translate = useTranslation();
const client = useClient();
@@ -169,4 +170,4 @@ export function Profile() {
</p>
</div>
);
}
});

View File

@@ -32,7 +32,8 @@ interface Session {
export function Sessions() {
const client = useContext(AppContext);
const deviceId = client.session?.id;
const deviceId =
typeof client.session === "object" ? client.session.id : undefined;
const [sessions, setSessions] = useState<Session[] | undefined>(undefined);
const [attemptingDelete, setDelete] = useState<string[]>([]);