From 29bb93f39910c234b59a25b04ec64e099513266e Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 22 Jun 2021 19:34:52 +0100 Subject: [PATCH] Remove twemoji dependency. Support re-connecting after going / starting offline. --- VERSION | 1 + package.json | 1 - publish.sh | 7 + src/components/common/Emoji.tsx | 37 ++++- .../common/messaging/embed/Embed.tsx | 17 -- .../navigation/items/Item.module.scss | 156 ------------------ .../intermediate/popovers/ImageViewer.tsx | 14 +- .../intermediate/popovers/UserProfile.tsx | 43 +++-- src/context/revoltjs/events.ts | 56 ++++--- src/version.ts | 2 +- vite.config.ts | 5 + yarn.lock | 45 ----- 12 files changed, 108 insertions(+), 276 deletions(-) create mode 100644 VERSION create mode 100644 publish.sh diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..c096572f --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0.0-vite \ No newline at end of file diff --git a/package.json b/package.json index d739a386..bce943b8 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,6 @@ "sass": "^1.35.1", "shade-blend-color": "^1.0.0", "styled-components": "^5.3.0", - "twemoji": "^13.1.0", "typescript": "^4.3.2", "ulid": "^2.3.0", "use-resize-observer": "^7.0.0", diff --git a/publish.sh b/publish.sh new file mode 100644 index 00000000..427d025d --- /dev/null +++ b/publish.sh @@ -0,0 +1,7 @@ +#!/bin/bash +version=$(cat VERSION) + + docker build -t revoltchat/client:${version} . && +docker tag revoltchat/client:${version} revoltchat/client:latest && + docker push revoltchat/client:${version} && + docker push revoltchat/client:latest diff --git a/src/components/common/Emoji.tsx b/src/components/common/Emoji.tsx index 74e381b5..791a0036 100644 --- a/src/components/common/Emoji.tsx +++ b/src/components/common/Emoji.tsx @@ -1,22 +1,43 @@ -import twemoji from 'twemoji'; +import { EmojiPacks } from '../../redux/reducers/settings'; var EMOJI_PACK = 'mutant'; const REVISION = 3; -/*export function setEmojiPack(pack: EmojiPacks) { +export function setEmojiPack(pack: EmojiPacks) { EMOJI_PACK = pack; -}*/ +} + +// Originally taken from Twemoji source code, +// re-written by bree to be more readable. +function codePoints(rune: string) { + const pairs = []; + let low = 0; + let i = 0; + + while (i < rune.length) { + const charCode = rune.charCodeAt(i++); + if (low) { + pairs.push(0x10000 + ((low - 0xd800) << 10) + (charCode - 0xdc00)); + low = 0; + } else if (0xd800 <= charCode && charCode <= 0xdbff) { + low = charCode; + } else { + pairs.push(charCode); + } + } + + return pairs; +} // Taken from Twemoji source code. // scripts/build.js#344 // grabTheRightIcon(rawText); const UFE0Fg = /\uFE0F/g; const U200D = String.fromCharCode(0x200D); -function toCodePoint(emoji: string) { - return twemoji.convert.toCodePoint(emoji.indexOf(U200D) < 0 ? - emoji.replace(UFE0Fg, '') : - emoji - ); +function toCodePoint(rune: string) { + return codePoints(rune.indexOf(U200D) < 0 ? rune.replace(UFE0Fg, '') : rune) + .map((val) => val.toString(16)) + .join("-") } function parseEmoji(emoji: string) { diff --git a/src/components/common/messaging/embed/Embed.tsx b/src/components/common/messaging/embed/Embed.tsx index 647731d4..f0bd8d78 100644 --- a/src/components/common/messaging/embed/Embed.tsx +++ b/src/components/common/messaging/embed/Embed.tsx @@ -52,23 +52,6 @@ export default function Embed({ embed }: Props) { switch (embed.type) { case 'Website': { - // ! FIXME: move this to january - /*if (embed.url && YOUTUBE_RE.test(embed.url)) { - embed.color = '#FF424F'; - } - - if (embed.url && TWITCH_RE.test(embed.url)) { - embed.color = '#7B68EE'; - } - - if (embed.url && SPOTIFY_RE.test(embed.url)) { - embed.color = '#1ABC9C'; - } - - if (embed.url && SOUNDCLOUD_RE.test(embed.url)) { - embed.color = '#FF7F50'; - }*/ - // Determine special embed size. let mw, mh; let largeMedia = (embed.special && embed.special.type !== 'None') || embed.image?.size === 'Large'; diff --git a/src/components/navigation/items/Item.module.scss b/src/components/navigation/items/Item.module.scss index d06e98f4..27116ebc 100644 --- a/src/components/navigation/items/Item.module.scss +++ b/src/components/navigation/items/Item.module.scss @@ -145,159 +145,3 @@ background: var(--error); } } - -/* ! FIXME: check if anything is missing, then remove this block -.olditem { - display: flex; - user-select: none; - align-items: center; - flex-direction: row; - - gap: 8px; - height: 48px; - padding: 0 8px; - cursor: pointer; - font-size: 16px; - border-radius: 6px; - box-sizing: content-box; - transition: .1s ease background-color; - - color: var(--tertiary-foreground); - stroke: var(--tertiary-foreground); - - .avatar { - flex-shrink: 0; - height: 32px; - flex-shrink: 0; - padding: 10px 0; - box-sizing: content-box; - - img { - width: 32px; - height: 32px; - border-radius: 50%; - } - } - - div { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - transition: color .1s ease-in-out; - - &.content { - gap: 8px; - flex-grow: 1; - min-width: 0; - display: flex; - align-items: center; - flex-direction: row; - - svg { - flex-shrink: 0; - } - - span { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } - - &.name { - flex-grow: 1; - display: flex; - flex-direction: column; - font-size: .90625rem; - font-weight: 600; - - .subText { - font-size: .6875rem; - margin-top: -1px; - color: var(--tertiary-foreground); - font-weight: 500; - } - } - - &.unread { - width: 6px; - height: 6px; - margin: 9px; - flex-shrink: 0; - border-radius: 50%; - background: var(--foreground); - } - - &.button { - flex-shrink: 0; - - .icon { - opacity: 0; - display: none; - transition: 0.1s ease opacity; - } - } - } - - &[data-active="true"] { - color: var(--foreground); - stroke: var(--foreground); - background: var(--hover); - cursor: default; - - .subText { - color: var(--secondary-foreground) !important; - } - - .unread { - display: none; - } - } - - &[data-alert="true"] { - color: var(--secondary-foreground); - } - - &[data-type="user"] { - opacity: 0.4; - color: var(--foreground); - transition: 0.15s ease opacity; - cursor: pointer; - - &[data-online="true"], - &:hover { - opacity: 1; - //background: none; - } - } - - &[data-size="compact"] { - margin-bottom: 2px; - height: 32px; - transition: border-inline-start .1s ease-in-out; - border-inline-start: 4px solid transparent; - - &[data-active="true"] { - border-inline-start: 4px solid var(--accent); - border-radius: 4px; - } - } - - &[data-size="small"] { - margin-bottom: 2px; - height: 42px; - } - - &:hover { - background: var(--hover); - - div.button .unread { - display: none; - } - - div.button .icon { - opacity: 1; - display: block; - } - } -}*/ diff --git a/src/context/intermediate/popovers/ImageViewer.tsx b/src/context/intermediate/popovers/ImageViewer.tsx index ae6754e2..e42d6ca1 100644 --- a/src/context/intermediate/popovers/ImageViewer.tsx +++ b/src/context/intermediate/popovers/ImageViewer.tsx @@ -3,6 +3,8 @@ import Modal from "../../../components/ui/Modal"; import { useContext, useEffect } from "preact/hooks"; import { AppContext } from "../../revoltjs/RevoltClient"; import { Attachment, EmbedImage } from "revolt.js/dist/api/objects"; +import EmbedMediaActions from "../../../components/common/messaging/embed/EmbedMediaActions"; +import AttachmentActions from "../../../components/common/messaging/attachments/AttachmentActions"; interface Props { onClose: () => void; @@ -11,6 +13,12 @@ interface Props { } export function ImageViewer({ attachment, embed, onClose }: Props) { + // ! FIXME: temp code + // ! add proxy function to client + function proxyImage(url: string) { + return 'https://jan.revolt.chat/proxy?url=' + encodeURIComponent(url); + } + if (attachment && attachment.metadata.type !== "Image") return null; const client = useContext(AppContext); @@ -31,13 +39,13 @@ export function ImageViewer({ attachment, embed, onClose }: Props) { { attachment && <> - {/**/} + } { embed && <> - {/**/} - {/**/} + + } diff --git a/src/context/intermediate/popovers/UserProfile.tsx b/src/context/intermediate/popovers/UserProfile.tsx index 2bcddb36..385829a7 100644 --- a/src/context/intermediate/popovers/UserProfile.tsx +++ b/src/context/intermediate/popovers/UserProfile.tsx @@ -1,22 +1,24 @@ import { decodeTime } from "ulid"; +import { Link, useHistory } from "react-router-dom"; import { Localizer, Text } from "preact-i18n"; import styles from "./UserProfile.module.scss"; import Modal from "../../../components/ui/Modal"; import { Route } from "revolt.js/dist/api/routes"; import { Users } from "revolt.js/dist/api/objects"; import { useIntermediate } from "../Intermediate"; -import { Link, useHistory } from "react-router-dom"; import { CashStack } from "@styled-icons/bootstrap"; import Preloader from "../../../components/ui/Preloader"; import Tooltip from '../../../components/common/Tooltip'; +import IconButton from "../../../components/ui/IconButton"; import Markdown from '../../../components/markdown/Markdown'; +import { UserPermission } from "revolt.js/dist/api/permissions"; import UserIcon from '../../../components/common/user/UserIcon'; import ChannelIcon from '../../../components/common/ChannelIcon'; import UserStatus from '../../../components/common/user/UserStatus'; import { Mail, Edit, UserPlus, Shield } from "@styled-icons/feather"; -import { useChannels, useForceUpdate, useUsers } from "../../revoltjs/hooks"; import { useContext, useEffect, useLayoutEffect, useState } from "preact/hooks"; import { AppContext, ClientStatus, StatusContext } from "../../revoltjs/RevoltClient"; +import { useChannels, useForceUpdate, useUserPermission, useUsers } from "../../revoltjs/hooks"; interface Props { user_id: string; @@ -43,23 +45,25 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) { undefined | null | Route<"GET", "/users/id/mutual">["response"] >(undefined); + const history = useHistory(); const client = useContext(AppContext); const status = useContext(StatusContext); const [tab, setTab] = useState("profile"); - const history = useHistory(); const ctx = useForceUpdate(); const all_users = useUsers(undefined, ctx); const channels = useChannels(undefined, ctx); - + const user = all_users.find(x => x!._id === user_id); const users = mutual?.users ? all_users.filter(x => mutual.users.includes(x!._id)) : undefined; - + if (!user) { useEffect(onClose, []); return null; } + const permissions = useUserPermission(user!._id, ctx); + useLayoutEffect(() => { if (!user_id) return; if (typeof profile !== 'undefined') setProfile(undefined); @@ -93,17 +97,12 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) { ) { setProfile(null); - // ! FIXME: in the future, also check if mutual guilds - // ! maybe just allow mutual group to allow profile viewing - /*if ( - user.relationship === Users.Relationship.Friend || - user.relationship === Users.Relationship.User - ) {*/ + if (permissions & UserPermission.ViewProfile) { client.users .fetchProfile(user_id) .then(data => setProfile(data)) .catch(() => {}); - //} + } } }, [profile, status]); @@ -157,35 +156,31 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) { } > - {/* { onClose(); history.push(`/open/${user_id}`); - }} - >*/} + }}> - {/**/} + )} {user.relationship === Users.Relationship.User && ( - /* { onClose(); if (dummy) return; history.push(`/settings/profile`); - }} - >*/ + }}> - /**/ + )} {(user.relationship === Users.Relationship.Incoming || user.relationship === Users.Relationship.None) && ( - /* client.users.addFriend(user.username)} - >*/ + client.users.addFriend(user.username)}> - /**/ + )}
diff --git a/src/context/revoltjs/events.ts b/src/context/revoltjs/events.ts index b6fba620..b97375f8 100644 --- a/src/context/revoltjs/events.ts +++ b/src/context/revoltjs/events.ts @@ -18,23 +18,28 @@ export function registerEvents({ operations, dispatcher }: { operations: ClientOperations } & WithDispatcher, setStatus: StateUpdater, client: Client) { + function attemptReconnect() { + if (preventReconnect) return; + function reconnect() { + preventUntil = +new Date() + 2000; + client.websocket.connect().catch(err => console.error(err)); + } + + if (+new Date() > preventUntil) { + setTimeout(reconnect, 2000); + } else { + reconnect(); + } + } + const listeners = { connecting: () => operations.ready() && setStatus(ClientStatus.CONNECTING), dropped: () => { - operations.ready() && setStatus(ClientStatus.DISCONNECTED); - - if (preventReconnect) return; - function reconnect() { - preventUntil = +new Date() + 2000; - client.websocket.connect().catch(err => console.error(err)); - } - - if (+new Date() > preventUntil) { - setTimeout(reconnect, 2000); - } else { - reconnect(); + if (operations.ready()) { + setStatus(ClientStatus.DISCONNECTED); + attemptReconnect(); } }, @@ -79,9 +84,7 @@ export function registerEvents({ } }, - ready: () => { - setStatus(ClientStatus.ONLINE); - } + ready: () => setStatus(ClientStatus.ONLINE) }; let listenerFunc: { [key: string]: Function }; @@ -101,20 +104,31 @@ export function registerEvents({ client.addListener(listener, (listenerFunc as any)[listener]); } - /*const online = () => - operations.ready() && setStatus(ClientStatus.RECONNECTING); - const offline = () => - operations.ready() && setStatus(ClientStatus.OFFLINE); + const online = () => { + if (operations.ready()) { + setStatus(ClientStatus.RECONNECTING); + setReconnectDisallowed(false); + attemptReconnect(); + } + }; + + const offline = () => { + if (operations.ready()) { + setReconnectDisallowed(true); + client.websocket.disconnect(); + setStatus(ClientStatus.OFFLINE); + } + }; window.addEventListener("online", online); window.addEventListener("offline", offline); return () => { for (const listener of Object.keys(listenerFunc)) { - RevoltClient.removeListener(listener, (listenerFunc as any)[listener]); + client.removeListener(listener, (listenerFunc as any)[listener]); } window.removeEventListener("online", online); window.removeEventListener("offline", offline); - };*/ + }; } diff --git a/src/version.ts b/src/version.ts index 4c86db39..63b6810d 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const APP_VERSION = "1.0.0-vite"; +export const APP_VERSION = "__APP_VERSION__"; diff --git a/vite.config.ts b/vite.config.ts index 8da84488..e797ce48 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,6 +19,10 @@ function getGitRevision() { } } +function getVersion() { + return readFileSync('VERSION').toString(); +} + export default defineConfig({ plugins: [ preact(), @@ -51,6 +55,7 @@ export default defineConfig({ }), replace({ __GIT_REVISION__: getGitRevision(), + __APP_VERSION__: getVersion(), preventAssignment: true }) ], diff --git a/yarn.lock b/yarn.lock index 31f59fe4..18f56c48 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2252,15 +2252,6 @@ from@~0: resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= -fs-extra@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^9.0.1: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -2648,22 +2639,6 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922" - integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w== - dependencies: - universalify "^0.1.2" - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -3778,21 +3753,6 @@ tsutils@^3.17.1, tsutils@^3.21.0: dependencies: tslib "^1.8.1" -twemoji-parser@13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.1.0.tgz#65e7e449c59258791b22ac0b37077349127e3ea4" - integrity sha512-AQOzLJpYlpWMy8n+0ATyKKZzWlZBJN+G0C+5lhX7Ftc2PeEVdUU/7ns2Pn2vVje26AIZ/OHwFoUbdv6YYD/wGg== - -twemoji@^13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/twemoji/-/twemoji-13.1.0.tgz#65bb71e966dae56f0d42c30176f04cbdae109913" - integrity sha512-e3fZRl2S9UQQdBFLYXtTBT6o4vidJMnpWUAhJA+yLGR+kaUTZAt3PixC0cGvvxWSuq2MSz/o0rJraOXrWw/4Ew== - dependencies: - fs-extra "^8.0.1" - jsonfile "^5.0.0" - twemoji-parser "13.1.0" - universalify "^0.1.2" - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -3870,11 +3830,6 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -universalify@^0.1.0, universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"