Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
// eslint-disable-next-line @typescript-eslint/no-unused-vars
/* eslint-disable */
import JSX = preact.JSX;
import localForage from "localforage";
import { createStore } from "redux";
import { Core } from "revolt.js/dist/api/objects";
import { RevoltConfiguration } from "revolt-api/types/Core";
import { Language } from "../context/Locale";
......@@ -14,17 +14,15 @@ import { QueuedMessage } from "./reducers/queue";
import { SectionToggle } from "./reducers/section_toggle";
import { Settings } from "./reducers/settings";
import { SyncOptions } from "./reducers/sync";
import { Typing } from "./reducers/typing";
import { Unreads } from "./reducers/unreads";
export type State = {
config: Core.RevoltNodeConfiguration;
config: RevoltConfiguration;
locale: Language;
auth: AuthState;
settings: Settings;
unreads: Unreads;
queue: QueuedMessage[];
typing: Typing;
drafts: Drafts;
sync: SyncOptions;
experiments: ExperimentOptions;
......
import type { Auth } from "revolt.js/dist/api/objects";
import { Session } from "revolt-api/types/Auth";
export interface AuthState {
accounts: {
[key: string]: {
session: Auth.Session;
session: Session;
};
};
active?: string;
......@@ -13,7 +13,7 @@ export type AuthAction =
| { type: undefined }
| {
type: "LOGIN";
session: Auth.Session;
session: Session;
}
| {
type: "LOGOUT";
......
export type Experiments = "search";
export const AVAILABLE_EXPERIMENTS: Experiments[] = ['search'];
export const AVAILABLE_EXPERIMENTS: Experiments[] = ["search"];
export const EXPERIMENTS: {
[key in Experiments]: { title: string; description: string };
} = {
......
......@@ -12,7 +12,6 @@ import { sectionToggle, SectionToggleAction } from "./section_toggle";
import { config, ConfigAction } from "./server_config";
import { settings, SettingsAction } from "./settings";
import { sync, SyncAction } from "./sync";
import { typing, TypingAction } from "./typing";
import { unreads, UnreadsAction } from "./unreads";
export default combineReducers({
......@@ -22,7 +21,6 @@ export default combineReducers({
settings,
unreads,
queue,
typing,
drafts,
sync,
experiments,
......@@ -38,7 +36,6 @@ export type Action =
| SettingsAction
| UnreadsAction
| QueueAction
| TypingAction
| DraftAction
| SyncAction
| ExperimentsAction
......
import type { Channel, Message } from "revolt.js";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import type { SyncUpdateAction } from "./sync";
......@@ -35,7 +36,7 @@ export function shouldNotify(
case "none":
return false;
case "mention": {
if (!message.mentions?.includes(user_id)) return false;
if (!message.mention_ids?.includes(user_id)) return false;
}
}
......
import type { MessageObject } from "../../context/revoltjs/util";
export enum QueueStatus {
SENDING = "sending",
ERRORED = "errored",
......@@ -10,7 +8,11 @@ export interface Reply {
mention: boolean;
}
export type QueuedMessageData = Omit<MessageObject, "content" | "replies"> & {
export type QueuedMessageData = {
_id: string;
author: string;
channel: string;
content: string;
replies: Reply[];
};
......
import type { Core } from "revolt.js/dist/api/objects";
import type { RevoltConfiguration } from "revolt-api/types/Core";
export type ConfigAction =
| { type: undefined }
| {
type: "SET_CONFIG";
config: Core.RevoltNodeConfiguration;
config: RevoltConfiguration;
};
export function config(
state = {} as Core.RevoltNodeConfiguration,
state = {} as RevoltConfiguration,
action: ConfigAction,
): Core.RevoltNodeConfiguration {
): RevoltConfiguration {
switch (action.type) {
case "SET_CONFIG":
return action.config;
......
export type TypingUser = { id: string; started: number };
export type Typing = { [key: string]: TypingUser[] };
export type TypingAction =
| { type: undefined }
| {
type: "TYPING_START";
channel: string;
user: string;
}
| {
type: "TYPING_STOP";
channel: string;
user: string;
}
| {
type: "RESET";
};
export function typing(state: Typing = {}, action: TypingAction): Typing {
switch (action.type) {
case "TYPING_START":
return {
...state,
[action.channel]: [
...(state[action.channel] ?? []).filter(
(x) => x.id !== action.user,
),
{
id: action.user,
started: +new Date(),
},
],
};
case "TYPING_STOP":
return {
...state,
[action.channel]:
state[action.channel]?.filter(
(x) => x.id !== action.user,
) ?? [],
};
case "RESET":
return {};
default:
return state;
}
}
import type { Sync } from "revolt.js/dist/api/objects";
import type { ChannelUnread } from "revolt-api/types/Sync";
export interface Unreads {
[key: string]: Partial<Omit<Sync.ChannelUnread, "_id">>;
[key: string]: Partial<Omit<ChannelUnread, "_id">>;
}
export type UnreadsAction =
......@@ -13,7 +13,7 @@ export type UnreadsAction =
}
| {
type: "UNREADS_SET";
unreads: Sync.ChannelUnread[];
unreads: ChannelUnread[];
}
| {
type: "UNREADS_MENTION";
......
/* eslint-disable */
// Strings needs to be explictly stated here as they can cause type issues elsewhere.
export const REPO_URL: string =
"https://gitlab.insrt.uk/revolt/revite/-/commit";
export const GIT_REVISION: string = "__GIT_REVISION__";
......
......@@ -16,6 +16,10 @@
background: var(--scrollbar-thumb);
}
::-webkit-scrollbar-corner {
background: transparent;
}
::selection {
background: var(--accent);
color: var(--foreground);
......@@ -44,3 +48,7 @@ hr {
height: 1px;
flex-grow: 1;
}
foreignObject > svg {
vertical-align: top !important;
}
......@@ -7,13 +7,20 @@
--font: "Open Sans";
--codeblock-font: "Fira Code";
--sidebar-active: var(--secondary-background);
/**
* Native
*/
--titlebar-height: 29px;
--titlebar-action-padding: 8px;
--titlebar-logo-color: var(--secondary-foreground);
/**
* Layout
*/
--app-height: 100vh;
--border-radius: 6px;
--input-border-width: 2px;
--textarea-padding: 16px;
--textarea-line-height: 20px;
......@@ -29,6 +36,13 @@
/**
* Experimental
*/
--background-rgb: (25,25,25); //THIS IS SO THAT WE CAN HAVE CUSTOM BACKGROUNDS FOR THE CLIENT, CONVERTS THE HEX TO AN RGB VALUE FROM --background
--background-rgba: rgba(var(--background-rgb), .8); //make the opacity also customizable
--background-rgb: (
25,
25,
25
); //THIS IS SO THAT WE CAN HAVE CUSTOM BACKGROUNDS FOR THE CLIENT, CONVERTS THE HEX TO AN RGB VALUE FROM --background
--background-rgba: rgba(
var(--background-rgb),
0.8
); //make the opacity also customizable
}
/// <reference lib="webworker" />
import { IDBPDatabase, openDB } from "idb";
import { getItem } from "localforage";
import { Channel, Message, User } from "revolt.js";
import { Server } from "revolt.js/dist/api/objects";
import { precacheAndRoute } from "workbox-precaching";
import type { State } from "./redux";
import {
getNotificationState,
shouldNotify,
} from "./redux/reducers/notifications";
declare let self: ServiceWorkerGlobalScope;
self.addEventListener("message", (event) => {
......@@ -19,130 +9,10 @@ self.addEventListener("message", (event) => {
precacheAndRoute(self.__WB_MANIFEST);
// ulid decodeTime(id: string)
// since crypto is not available in sw.js
const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
const ENCODING_LEN = ENCODING.length;
const TIME_LEN = 10;
function decodeTime(id: string) {
const time = id
.substr(0, TIME_LEN)
.split("")
.reverse()
.reduce((carry, char, index) => {
const encodingIndex = ENCODING.indexOf(char);
if (encodingIndex === -1) throw `invalid character found: ${char}`;
return (carry += encodingIndex * Math.pow(ENCODING_LEN, index));
}, 0);
return time;
}
self.addEventListener("push", (event) => {
async function process() {
if (event.data === null) return;
const data: Message = event.data.json();
const item = await localStorage.getItem("state");
if (!item) return;
const state: State = JSON.parse(item);
const autumn_url = state.config.features.autumn.url;
const user_id = state.auth.active!;
let db: IDBPDatabase;
try {
// Match RevoltClient.tsx#L55
db = await openDB("state", 3, {
upgrade(db) {
for (const store of [
"channels",
"servers",
"users",
"members",
]) {
db.createObjectStore(store, {
keyPath: "_id",
});
}
},
});
} catch (err) {
console.error(
"Failed to open IndexedDB store, continuing without.",
);
return;
}
async function get<T>(
store: string,
key: string,
): Promise<T | undefined> {
try {
return await db.get(store, key);
} catch (err) {
return undefined;
}
}
const channel = await get<Channel>("channels", data.channel);
const user = await get<User>("users", data.author);
if (channel) {
const notifs = getNotificationState(state.notifications, channel);
if (!shouldNotify(notifs, data, user_id)) return;
}
let title = `@${data.author}`;
const username = user?.username ?? data.author;
let image;
if (data.attachments) {
const attachment = data.attachments[0];
if (attachment.metadata.type === "Image") {
image = `${autumn_url}/${attachment.tag}/${attachment._id}`;
}
}
switch (channel?.channel_type) {
case "SavedMessages":
break;
case "DirectMessage":
title = `@${username}`;
break;
case "Group":
if (user?._id === "00000000000000000000000000") {
title = channel.name;
} else {
title = `@${user?.username} - ${channel.name}`;
}
break;
case "TextChannel":
{
const server = await get<Server>("servers", channel.server);
title = `@${user?.username} (#${channel.name}, ${server?.name})`;
}
break;
}
await self.registration.showNotification(title, {
icon: user?.avatar
? `${autumn_url}/${user.avatar.tag}/${user.avatar._id}`
: `https://api.revolt.chat/users/${data.author}/default_avatar`,
image,
body:
typeof data.content === "string"
? data.content
: JSON.stringify(data.content),
timestamp: decodeTime(data._id),
tag: data.channel,
badge: "https://app.revolt.chat/assets/icons/mono-48x48.png",
data:
channel?.channel_type === "TextChannel"
? `/server/${channel.server}/channel/${channel._id}`
: `/channel/${data.channel}`,
});
// Need to write notification generator on server.
}
event.waitUntil(process());
......
import { resolve } from 'path'
import { readFileSync } from 'fs'
import { defineConfig } from 'vite'
import preact from '@preact/preset-vite'
import { VitePWA } from 'vite-plugin-pwa'
import replace from '@rollup/plugin-replace'
import replace from "@rollup/plugin-replace";
import { readFileSync } from "fs";
import { resolve } from "path";
import { defineConfig } from "vite";
import { VitePWA } from "vite-plugin-pwa";
import preact from "@preact/preset-vite";
function getGitRevision() {
try {
const rev = readFileSync('.git/HEAD').toString().trim();
if (rev.indexOf(':') === -1) {
return rev;
} else {
return readFileSync('.git/' + rev.substring(5)).toString().trim();
try {
const rev = readFileSync(".git/HEAD").toString().trim();
if (rev.indexOf(":") === -1) {
return rev;
} else {
return readFileSync(".git/" + rev.substring(5))
.toString()
.trim();
}
} catch (err) {
console.error("Failed to get Git revision.");
return "?";
}
} catch (err) {
console.error('Failed to get Git revision.');
return '?';
}
}
function getGitBranch() {
try {
const rev = readFileSync('.git/HEAD').toString().trim();
if (rev.indexOf(':') === -1) {
return 'DETACHED';
} else {
return rev.split('/').pop();
try {
const rev = readFileSync(".git/HEAD").toString().trim();
if (rev.indexOf(":") === -1) {
return "DETACHED";
} else {
return rev.split("/").pop();
}
} catch (err) {
console.error("Failed to get Git branch.");
return "?";
}
} catch (err) {
console.error('Failed to get Git branch.');
return '?';
}
}
function getVersion() {
return readFileSync('VERSION').toString();
return readFileSync("VERSION").toString();
}
const branch = getGitBranch();
const isNightly = false;//branch !== 'production';
const iconPrefix = isNightly ? 'nightly-' : '';
const isNightly = false; //branch !== 'production';
const iconPrefix = isNightly ? "nightly-" : "";
export default defineConfig({
plugins: [
preact(),
VitePWA({
srcDir: 'src',
filename: 'sw.ts',
strategies: 'injectManifest',
manifest: {
name: isNightly ? "Revolt Nightly" : "Revolt",
short_name: "Revolt",
description: isNightly ? "Early preview builds of Revolt." : "User-first, privacy-focused chat platform.",
categories: ["messaging"],
start_url: "/",
orientation: "portrait",
display: "standalone",
background_color: "#101823",
theme_color: "#101823",
icons: [
{
"src": `/assets/icons/${iconPrefix}android-chrome-192x192.png`,
"type": "image/png",
"sizes": "192x192"
},
{
"src": `/assets/icons/${iconPrefix}android-chrome-512x512.png`,
"type": "image/png",
"sizes": "512x512"
plugins: [
preact(),
VitePWA({
srcDir: "src",
filename: "sw.ts",
strategies: "injectManifest",
manifest: {
name: isNightly ? "Revolt Nightly" : "Revolt",
short_name: "Revolt",
description: isNightly
? "Early preview builds of Revolt."
: "User-first, privacy-focused chat platform.",
categories: ["messaging"],
start_url: "/",
orientation: "portrait",
display: "standalone",
background_color: "#101823",
theme_color: "#101823",
icons: [
{
src: `/assets/icons/${iconPrefix}android-chrome-192x192.png`,
type: "image/png",
sizes: "192x192",
},
{
src: `/assets/icons/${iconPrefix}android-chrome-512x512.png`,
type: "image/png",
sizes: "512x512",
},
{
src: `/assets/icons/monochrome.svg`,
type: "image/svg+xml",
sizes: "48x48 72x72 96x96 128x128 256x256",
purpose: "monochrome",
},
{
src: `/assets/icons/masking-512x512.png`,
type: "image/png",
sizes: "512x512",
purpose: "maskable",
},
],
},
{
"src": `/assets/icons/monochrome.svg`,
"type": "image/svg+xml",
"sizes": "48x48 72x72 96x96 128x128 256x256",
"purpose": "monochrome"
}),
replace({
__GIT_REVISION__: getGitRevision(),
__GIT_BRANCH__: getGitBranch(),
__APP_VERSION__: getVersion(),
preventAssignment: true,
}),
],
build: {
sourcemap: true,
rollupOptions: {
input: {
main: resolve(__dirname, "index.html"),
ui: resolve(__dirname, "ui/index.html"),
},
{
"src": `/assets/icons/masking-512x512.png`,
"type": "image/png",
"sizes": "512x512",
"purpose": "maskable"
}
]
}
}),
replace({
__GIT_REVISION__: getGitRevision(),
__GIT_BRANCH__: getGitBranch(),
__APP_VERSION__: getVersion(),
preventAssignment: true
})
],
build: {
sourcemap: true,
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
ui: resolve(__dirname, 'ui/index.html')
}
}
}
})
},
},
});
......@@ -879,6 +879,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.14.8":
version "7.14.8"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446"
integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.12.13", "@babel/template@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
......@@ -1114,14 +1121,6 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
"@insertish/mutable@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@insertish/mutable/-/mutable-1.1.0.tgz#06f95f855691ccb69ee3c339887a80bcd1498116"
integrity sha512-NH7aCGFAKRE1gFprrW/HsJoWCWQy18TZBarxLdeLVWdLFvkb2lD6Z5B70oOoUHFNpykiTC8IcRonsd9Xn13n8Q==
dependencies:
eventemitter3 "^4.0.7"
lodash.isequal "^4.5.0"
"@mdn/browser-compat-data@^2.0.7":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-2.0.7.tgz#72ec37b9c1e00ce0b4e0309d753be18e2da12ee3"
......@@ -1252,12 +1251,12 @@
"@babel/runtime" "^7.14.0"
"@styled-icons/styled-icon" "^10.6.3"
"@styled-icons/boxicons-solid@^10.34.0":
version "10.34.0"
resolved "https://registry.yarnpkg.com/@styled-icons/boxicons-solid/-/boxicons-solid-10.34.0.tgz#4f31b873a1d52c85230f86eb7106c04f416a12c9"
integrity sha512-0DTsuysRgIO/XoSq5sFPeknnidLzhTEmaG5uJuLmCPBw78VjxNt6DQFRcn8ytn+ba5Qhu+Ps3Km8nbY7Zf14/g==
"@styled-icons/boxicons-solid@^10.37.0":
version "10.37.0"
resolved "https://registry.yarnpkg.com/@styled-icons/boxicons-solid/-/boxicons-solid-10.37.0.tgz#49e3ec72b560967f1ba12c433f28270d8a74e9b9"
integrity sha512-u6/urwIWesGArSHW98TFHnzMduInQYkhWE1LdNCWkmzs0CvQ0Xmmvnl1Lz9LnAHatQR+UFpKLz2y08Fhu7zBgQ==
dependencies:
"@babel/runtime" "^7.14.0"
"@babel/runtime" "^7.14.8"
"@styled-icons/styled-icon" "^10.6.3"
"@styled-icons/simple-icons@^10.33.0":
......@@ -2614,11 +2613,6 @@ hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-
dependencies:
react-is "^16.7.0"
idb@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/idb/-/idb-6.1.2.tgz#82ef5c951b8e1f47875d36ccafa4bedafc62f2f1"
integrity sha512-1DNDVu3yDhAZkFDlJf0t7r+GLZ248F5pTAtA7V0oVG3yjmV125qZOx3g0XpAEkGZVYQiFDAsSOnGet2bhugc3w==
ignore@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
......@@ -3298,7 +3292,7 @@ preact-markup@^2.0.0:
resolved "https://registry.yarnpkg.com/preact-markup/-/preact-markup-2.1.1.tgz#0451e7eed1dac732d7194c34a7f16ff45a2cfdd7"
integrity sha512-8JL2p36mzK8XkspOyhBxUSPjYwMxDM0L5BWBZWxsZMVW8WsGQrYQDgVuDKkRspt2hwrle+Cxr/053hpc9BJwfw==
preact@^10.0.0, preact@^10.4.6, preact@^10.5.13:
preact@^10.0.0, preact@^10.4.6, preact@^10.5.14:
version "10.5.14"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.5.14.tgz#0b14a2eefba3c10a57116b90d1a65f5f00cd2701"
integrity sha512-KojoltCrshZ099ksUZ2OQKfbH66uquFoxHSbnwKbTJHeQNvx42EmC7wQVWNuDt6vC5s3nudRHFtKbpY4ijKlaQ==
......@@ -3573,17 +3567,23 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
revolt.js@^4.3.3-alpha.19:
version "4.3.3-alpha.19"
resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.19.tgz#02b0fe8c44b6b803f5314a2d40eda5d3481901d3"
integrity sha512-cpJGqAnAzCV33zuFqiOlRopqhSMhSUZISB7vdsgvjS6Aof1UrWpJJO+POnVxo20FvLM0tMFZaHIxdYeW798U9w==
revolt-api@0.5.1-alpha.10-patch.0:
version "0.5.1-alpha.10-patch.0"
resolved "https://registry.yarnpkg.com/revolt-api/-/revolt-api-0.5.1-alpha.10-patch.0.tgz#97d31bec7dfa4573567097443acb059c4feaac20"
integrity sha512-UyM890HkGlYNQOxpHuEpUsJHLt8Ujnjg9/zPEDGpbvS4iy0jmHX23Hh8tOCfb/ewxbNrtT3G1HpSWKOneW/vYg==
revolt.js@5.0.0-alpha.18:
version "5.0.0-alpha.18"
resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-5.0.0-alpha.18.tgz#fffd63a4f4f93a4a6422de6a68c1ba3f3f9b55e5"
integrity sha512-NVd00P4CYLVJf1AuYwo65mPeLaST/RdU7dMLFwCZPvQAHvyPwTfLekCc9dfKPT4BkS2sjF8Vxi2xUFpMRMZYfw==
dependencies:
"@insertish/mutable" "1.1.0"
axios "^0.19.2"
eventemitter3 "^4.0.7"
exponential-backoff "^3.1.0"
isomorphic-ws "^4.0.1"
lodash.defaultsdeep "^4.6.1"
lodash.isequal "^4.5.0"
mobx "^6.3.2"
tsc-watch "^4.1.0"
ulid "^2.3.0"
ws "^7.2.1"
......