Use tabWidth 4 without actual tabs.

This commit is contained in:
Paul
2021-07-05 11:25:20 +01:00
parent 7bd33d8d34
commit b5a11d5c8f
180 changed files with 16619 additions and 16622 deletions

View File

@@ -1,49 +1,49 @@
import type { Auth } from "revolt.js/dist/api/objects";
export interface AuthState {
accounts: {
[key: string]: {
session: Auth.Session;
};
};
active?: string;
accounts: {
[key: string]: {
session: Auth.Session;
};
};
active?: string;
}
export type AuthAction =
| { type: undefined }
| {
type: "LOGIN";
session: Auth.Session;
}
| {
type: "LOGOUT";
user_id?: string;
};
| { type: undefined }
| {
type: "LOGIN";
session: Auth.Session;
}
| {
type: "LOGOUT";
user_id?: string;
};
export function auth(
state = { accounts: {} } as AuthState,
action: AuthAction,
state = { accounts: {} } as AuthState,
action: AuthAction,
): AuthState {
switch (action.type) {
case "LOGIN":
return {
accounts: {
...state.accounts,
[action.session.user_id]: {
session: action.session,
},
},
active: action.session.user_id,
};
case "LOGOUT": {
const accounts = Object.assign({}, state.accounts);
action.user_id && delete accounts[action.user_id];
switch (action.type) {
case "LOGIN":
return {
accounts: {
...state.accounts,
[action.session.user_id]: {
session: action.session,
},
},
active: action.session.user_id,
};
case "LOGOUT": {
const accounts = Object.assign({}, state.accounts);
action.user_id && delete accounts[action.user_id];
return {
accounts,
};
}
default:
return state;
}
return {
accounts,
};
}
default:
return state;
}
}

View File

@@ -1,35 +1,35 @@
export type Drafts = { [key: string]: string };
export type DraftAction =
| { type: undefined }
| {
type: "SET_DRAFT";
channel: string;
content: string;
}
| {
type: "CLEAR_DRAFT";
channel: string;
}
| {
type: "RESET";
};
| { type: undefined }
| {
type: "SET_DRAFT";
channel: string;
content: string;
}
| {
type: "CLEAR_DRAFT";
channel: string;
}
| {
type: "RESET";
};
export function drafts(state: Drafts = {}, action: DraftAction): Drafts {
switch (action.type) {
case "SET_DRAFT":
return {
...state,
[action.channel]: action.content,
};
case "CLEAR_DRAFT": {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [action.channel]: _, ...newState } = state;
return newState;
}
case "RESET":
return {};
default:
return state;
}
switch (action.type) {
case "SET_DRAFT":
return {
...state,
[action.channel]: action.content,
};
case "CLEAR_DRAFT": {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [action.channel]: _, ...newState } = state;
return newState;
}
case "RESET":
return {};
default:
return state;
}
}

View File

@@ -2,43 +2,43 @@ export type Experiments = never;
export const AVAILABLE_EXPERIMENTS: Experiments[] = [];
export interface ExperimentOptions {
enabled?: Experiments[];
enabled?: Experiments[];
}
export type ExperimentsAction =
| { type: undefined }
| {
type: "EXPERIMENTS_ENABLE";
key: Experiments;
}
| {
type: "EXPERIMENTS_DISABLE";
key: Experiments;
};
| { type: undefined }
| {
type: "EXPERIMENTS_ENABLE";
key: Experiments;
}
| {
type: "EXPERIMENTS_DISABLE";
key: Experiments;
};
export function experiments(
state = {} as ExperimentOptions,
action: ExperimentsAction,
state = {} as ExperimentOptions,
action: ExperimentsAction,
): ExperimentOptions {
switch (action.type) {
case "EXPERIMENTS_ENABLE":
return {
...state,
enabled: [
...(state.enabled ?? [])
.filter((x) => AVAILABLE_EXPERIMENTS.includes(x))
.filter((v) => v !== action.key),
action.key,
],
};
case "EXPERIMENTS_DISABLE":
return {
...state,
enabled: state.enabled
?.filter((v) => v !== action.key)
.filter((x) => AVAILABLE_EXPERIMENTS.includes(x)),
};
default:
return state;
}
switch (action.type) {
case "EXPERIMENTS_ENABLE":
return {
...state,
enabled: [
...(state.enabled ?? [])
.filter((x) => AVAILABLE_EXPERIMENTS.includes(x))
.filter((v) => v !== action.key),
action.key,
],
};
case "EXPERIMENTS_DISABLE":
return {
...state,
enabled: state.enabled
?.filter((v) => v !== action.key)
.filter((x) => AVAILABLE_EXPERIMENTS.includes(x)),
};
default:
return state;
}
}

View File

@@ -16,45 +16,45 @@ import { typing, TypingAction } from "./typing";
import { unreads, UnreadsAction } from "./unreads";
export default combineReducers({
config,
locale,
auth,
settings,
unreads,
queue,
typing,
drafts,
sync,
experiments,
lastOpened,
notifications,
sectionToggle,
config,
locale,
auth,
settings,
unreads,
queue,
typing,
drafts,
sync,
experiments,
lastOpened,
notifications,
sectionToggle,
});
export type Action =
| ConfigAction
| LocaleAction
| AuthAction
| SettingsAction
| UnreadsAction
| QueueAction
| TypingAction
| DraftAction
| SyncAction
| ExperimentsAction
| LastOpenedAction
| NotificationsAction
| SectionToggleAction
| { type: "__INIT"; state: State };
| ConfigAction
| LocaleAction
| AuthAction
| SettingsAction
| UnreadsAction
| QueueAction
| TypingAction
| DraftAction
| SyncAction
| ExperimentsAction
| LastOpenedAction
| NotificationsAction
| SectionToggleAction
| { type: "__INIT"; state: State };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function filter(obj: any, keys: string[]) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const newObj: any = {};
for (const key of keys) {
const v = obj[key];
if (v) newObj[key] = v;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const newObj: any = {};
for (const key of keys) {
const v = obj[key];
if (v) newObj[key] = v;
}
return newObj;
return newObj;
}

View File

@@ -1,32 +1,32 @@
export interface LastOpened {
[key: string]: string;
[key: string]: string;
}
export type LastOpenedAction =
| { type: undefined }
| {
type: "LAST_OPENED_SET";
parent: string;
child: string;
}
| {
type: "RESET";
};
| { type: undefined }
| {
type: "LAST_OPENED_SET";
parent: string;
child: string;
}
| {
type: "RESET";
};
export function lastOpened(
state = {} as LastOpened,
action: LastOpenedAction,
state = {} as LastOpened,
action: LastOpenedAction,
): LastOpened {
switch (action.type) {
case "LAST_OPENED_SET": {
return {
...state,
[action.parent]: action.child,
};
}
case "RESET":
return {};
default:
return state;
}
switch (action.type) {
case "LAST_OPENED_SET": {
return {
...state,
[action.parent]: action.child,
};
}
case "RESET":
return {};
default:
return state;
}
}

View File

@@ -3,50 +3,50 @@ import { Language } from "../../context/Locale";
import type { SyncUpdateAction } from "./sync";
export type LocaleAction =
| { type: undefined }
| {
type: "SET_LOCALE";
locale: Language;
}
| SyncUpdateAction;
| { type: undefined }
| {
type: "SET_LOCALE";
locale: Language;
}
| SyncUpdateAction;
export function findLanguage(lang?: string): Language {
if (!lang) {
if (typeof navigator === "undefined") {
lang = Language.ENGLISH;
} else {
lang = navigator.language;
}
}
if (!lang) {
if (typeof navigator === "undefined") {
lang = Language.ENGLISH;
} else {
lang = navigator.language;
}
}
const code = lang.replace("-", "_");
const short = code.split("_")[0];
const code = lang.replace("-", "_");
const short = code.split("_")[0];
const values = [];
for (const key in Language) {
const value = Language[key as keyof typeof Language];
values.push(value);
if (value.startsWith(code)) {
return value as Language;
}
}
const values = [];
for (const key in Language) {
const value = Language[key as keyof typeof Language];
values.push(value);
if (value.startsWith(code)) {
return value as Language;
}
}
for (const value of values.reverse()) {
if (value.startsWith(short)) {
return value as Language;
}
}
for (const value of values.reverse()) {
if (value.startsWith(short)) {
return value as Language;
}
}
return Language.ENGLISH;
return Language.ENGLISH;
}
export function locale(state = findLanguage(), action: LocaleAction): Language {
switch (action.type) {
case "SET_LOCALE":
return action.locale;
case "SYNC_UPDATE":
return (action.update.locale?.[1] ?? state) as Language;
default:
return state;
}
switch (action.type) {
case "SET_LOCALE":
return action.locale;
case "SYNC_UPDATE":
return (action.update.locale?.[1] ?? state) as Language;
default:
return state;
}
}

View File

@@ -5,78 +5,78 @@ import type { SyncUpdateAction } from "./sync";
export type NotificationState = "all" | "mention" | "none" | "muted";
export type Notifications = {
[key: string]: NotificationState;
[key: string]: NotificationState;
};
export const DEFAULT_STATES: {
[key in Channel["channel_type"]]: NotificationState;
[key in Channel["channel_type"]]: NotificationState;
} = {
SavedMessages: "all",
DirectMessage: "all",
Group: "all",
TextChannel: "mention",
VoiceChannel: "mention",
SavedMessages: "all",
DirectMessage: "all",
Group: "all",
TextChannel: "mention",
VoiceChannel: "mention",
};
export function getNotificationState(
notifications: Notifications,
channel: Channel,
notifications: Notifications,
channel: Channel,
) {
return notifications[channel._id] ?? DEFAULT_STATES[channel.channel_type];
return notifications[channel._id] ?? DEFAULT_STATES[channel.channel_type];
}
export function shouldNotify(
state: NotificationState,
message: Message,
user_id: string,
state: NotificationState,
message: Message,
user_id: string,
) {
switch (state) {
case "muted":
case "none":
return false;
case "mention": {
if (!message.mentions?.includes(user_id)) return false;
}
}
switch (state) {
case "muted":
case "none":
return false;
case "mention": {
if (!message.mentions?.includes(user_id)) return false;
}
}
return true;
return true;
}
export type NotificationsAction =
| { type: undefined }
| {
type: "NOTIFICATIONS_SET";
key: string;
state: NotificationState;
}
| {
type: "NOTIFICATIONS_REMOVE";
key: string;
}
| SyncUpdateAction
| {
type: "RESET";
};
| { type: undefined }
| {
type: "NOTIFICATIONS_SET";
key: string;
state: NotificationState;
}
| {
type: "NOTIFICATIONS_REMOVE";
key: string;
}
| SyncUpdateAction
| {
type: "RESET";
};
export function notifications(
state = {} as Notifications,
action: NotificationsAction,
state = {} as Notifications,
action: NotificationsAction,
): Notifications {
switch (action.type) {
case "NOTIFICATIONS_SET":
return {
...state,
[action.key]: action.state,
};
case "NOTIFICATIONS_REMOVE": {
const { [action.key]: _, ...newState } = state;
return newState;
}
case "SYNC_UPDATE":
return action.update.notifications?.[1] ?? state;
case "RESET":
return {};
default:
return state;
}
switch (action.type) {
case "NOTIFICATIONS_SET":
return {
...state,
[action.key]: action.state,
};
case "NOTIFICATIONS_REMOVE": {
const { [action.key]: _, ...newState } = state;
return newState;
}
case "SYNC_UPDATE":
return action.update.notifications?.[1] ?? state;
case "RESET":
return {};
default:
return state;
}
}

View File

@@ -1,113 +1,113 @@
import type { MessageObject } from "../../context/revoltjs/util";
export enum QueueStatus {
SENDING = "sending",
ERRORED = "errored",
SENDING = "sending",
ERRORED = "errored",
}
export interface Reply {
id: string;
mention: boolean;
id: string;
mention: boolean;
}
export type QueuedMessageData = Omit<MessageObject, "content" | "replies"> & {
content: string;
replies: Reply[];
content: string;
replies: Reply[];
};
export interface QueuedMessage {
id: string;
channel: string;
data: QueuedMessageData;
status: QueueStatus;
error?: string;
id: string;
channel: string;
data: QueuedMessageData;
status: QueueStatus;
error?: string;
}
export type QueueAction =
| { type: undefined }
| {
type: "QUEUE_ADD";
nonce: string;
channel: string;
message: QueuedMessageData;
}
| {
type: "QUEUE_FAIL";
nonce: string;
error: string;
}
| {
type: "QUEUE_START";
nonce: string;
}
| {
type: "QUEUE_REMOVE";
nonce: string;
}
| {
type: "QUEUE_DROP_ALL";
}
| {
type: "QUEUE_FAIL_ALL";
}
| {
type: "RESET";
};
| { type: undefined }
| {
type: "QUEUE_ADD";
nonce: string;
channel: string;
message: QueuedMessageData;
}
| {
type: "QUEUE_FAIL";
nonce: string;
error: string;
}
| {
type: "QUEUE_START";
nonce: string;
}
| {
type: "QUEUE_REMOVE";
nonce: string;
}
| {
type: "QUEUE_DROP_ALL";
}
| {
type: "QUEUE_FAIL_ALL";
}
| {
type: "RESET";
};
export function queue(
state: QueuedMessage[] = [],
action: QueueAction,
state: QueuedMessage[] = [],
action: QueueAction,
): QueuedMessage[] {
switch (action.type) {
case "QUEUE_ADD": {
return [
...state.filter((x) => x.id !== action.nonce),
{
id: action.nonce,
data: action.message,
channel: action.channel,
status: QueueStatus.SENDING,
},
];
}
case "QUEUE_FAIL": {
const entry = state.find(
(x) => x.id === action.nonce,
) as QueuedMessage;
return [
...state.filter((x) => x.id !== action.nonce),
{
...entry,
status: QueueStatus.ERRORED,
error: action.error,
},
];
}
case "QUEUE_START": {
const entry = state.find(
(x) => x.id === action.nonce,
) as QueuedMessage;
return [
...state.filter((x) => x.id !== action.nonce),
{
...entry,
status: QueueStatus.SENDING,
},
];
}
case "QUEUE_REMOVE":
return state.filter((x) => x.id !== action.nonce);
case "QUEUE_FAIL_ALL":
return state.map((x) => {
return {
...x,
status: QueueStatus.ERRORED,
};
});
case "QUEUE_DROP_ALL":
case "RESET":
return [];
default:
return state;
}
switch (action.type) {
case "QUEUE_ADD": {
return [
...state.filter((x) => x.id !== action.nonce),
{
id: action.nonce,
data: action.message,
channel: action.channel,
status: QueueStatus.SENDING,
},
];
}
case "QUEUE_FAIL": {
const entry = state.find(
(x) => x.id === action.nonce,
) as QueuedMessage;
return [
...state.filter((x) => x.id !== action.nonce),
{
...entry,
status: QueueStatus.ERRORED,
error: action.error,
},
];
}
case "QUEUE_START": {
const entry = state.find(
(x) => x.id === action.nonce,
) as QueuedMessage;
return [
...state.filter((x) => x.id !== action.nonce),
{
...entry,
status: QueueStatus.SENDING,
},
];
}
case "QUEUE_REMOVE":
return state.filter((x) => x.id !== action.nonce);
case "QUEUE_FAIL_ALL":
return state.map((x) => {
return {
...x,
status: QueueStatus.ERRORED,
};
});
case "QUEUE_DROP_ALL":
case "RESET":
return [];
default:
return state;
}
}

View File

@@ -1,40 +1,40 @@
export interface SectionToggle {
[key: string]: boolean;
[key: string]: boolean;
}
export type SectionToggleAction =
| { type: undefined }
| {
type: "SECTION_TOGGLE_SET";
id: string;
state: boolean;
}
| {
type: "SECTION_TOGGLE_UNSET";
id: string;
}
| {
type: "RESET";
};
| { type: undefined }
| {
type: "SECTION_TOGGLE_SET";
id: string;
state: boolean;
}
| {
type: "SECTION_TOGGLE_UNSET";
id: string;
}
| {
type: "RESET";
};
export function sectionToggle(
state = {} as SectionToggle,
action: SectionToggleAction,
state = {} as SectionToggle,
action: SectionToggleAction,
): SectionToggle {
switch (action.type) {
case "SECTION_TOGGLE_SET": {
return {
...state,
[action.id]: action.state,
};
}
case "SECTION_TOGGLE_UNSET": {
const { [action.id]: _, ...newState } = state;
return newState;
}
case "RESET":
return {};
default:
return state;
}
switch (action.type) {
case "SECTION_TOGGLE_SET": {
return {
...state,
[action.id]: action.state,
};
}
case "SECTION_TOGGLE_UNSET": {
const { [action.id]: _, ...newState } = state;
return newState;
}
case "RESET":
return {};
default:
return state;
}
}

View File

@@ -1,20 +1,20 @@
import type { Core } from "revolt.js/dist/api/objects";
export type ConfigAction =
| { type: undefined }
| {
type: "SET_CONFIG";
config: Core.RevoltNodeConfiguration;
};
| { type: undefined }
| {
type: "SET_CONFIG";
config: Core.RevoltNodeConfiguration;
};
export function config(
state = {} as Core.RevoltNodeConfiguration,
action: ConfigAction,
state = {} as Core.RevoltNodeConfiguration,
action: ConfigAction,
): Core.RevoltNodeConfiguration {
switch (action.type) {
case "SET_CONFIG":
return action.config;
default:
return state;
}
switch (action.type) {
case "SET_CONFIG":
return action.config;
default:
return state;
}
}

View File

@@ -7,106 +7,106 @@ import type { Sounds } from "../../assets/sounds/Audio";
import type { SyncUpdateAction } from "./sync";
export type SoundOptions = {
[key in Sounds]?: boolean;
[key in Sounds]?: boolean;
};
export const DEFAULT_SOUNDS: SoundOptions = {
message: true,
outbound: false,
call_join: true,
call_leave: true,
message: true,
outbound: false,
call_join: true,
call_leave: true,
};
export interface NotificationOptions {
desktopEnabled?: boolean;
sounds?: SoundOptions;
desktopEnabled?: boolean;
sounds?: SoundOptions;
}
export type EmojiPacks = "mutant" | "twemoji" | "noto" | "openmoji";
export interface AppearanceOptions {
emojiPack?: EmojiPacks;
emojiPack?: EmojiPacks;
}
export interface Settings {
theme?: ThemeOptions;
appearance?: AppearanceOptions;
notification?: NotificationOptions;
theme?: ThemeOptions;
appearance?: AppearanceOptions;
notification?: NotificationOptions;
}
export type SettingsAction =
| { type: undefined }
| {
type: "SETTINGS_SET_THEME";
theme: ThemeOptions;
}
| {
type: "SETTINGS_SET_THEME_OVERRIDE";
custom?: Partial<Theme>;
}
| {
type: "SETTINGS_SET_NOTIFICATION_OPTIONS";
options: NotificationOptions;
}
| {
type: "SETTINGS_SET_APPEARANCE";
options: Partial<AppearanceOptions>;
}
| SyncUpdateAction
| {
type: "RESET";
};
| { type: undefined }
| {
type: "SETTINGS_SET_THEME";
theme: ThemeOptions;
}
| {
type: "SETTINGS_SET_THEME_OVERRIDE";
custom?: Partial<Theme>;
}
| {
type: "SETTINGS_SET_NOTIFICATION_OPTIONS";
options: NotificationOptions;
}
| {
type: "SETTINGS_SET_APPEARANCE";
options: Partial<AppearanceOptions>;
}
| SyncUpdateAction
| {
type: "RESET";
};
export function settings(
state = {} as Settings,
action: SettingsAction,
state = {} as Settings,
action: SettingsAction,
): Settings {
setEmojiPack(state.appearance?.emojiPack ?? "mutant");
setEmojiPack(state.appearance?.emojiPack ?? "mutant");
switch (action.type) {
case "SETTINGS_SET_THEME":
return {
...state,
theme: {
...filter(state.theme, ["custom", "preset", "ligatures"]),
...action.theme,
},
};
case "SETTINGS_SET_THEME_OVERRIDE":
return {
...state,
theme: {
...state.theme,
custom: {
...state.theme?.custom,
...action.custom,
},
},
};
case "SETTINGS_SET_NOTIFICATION_OPTIONS":
return {
...state,
notification: {
...state.notification,
...action.options,
},
};
case "SETTINGS_SET_APPEARANCE":
return {
...state,
appearance: {
...filter(state.appearance, ["emojiPack"]),
...action.options,
},
};
case "SYNC_UPDATE":
return {
...state,
appearance: action.update.appearance?.[1] ?? state.appearance,
theme: action.update.theme?.[1] ?? state.theme,
};
case "RESET":
return {};
default:
return state;
}
switch (action.type) {
case "SETTINGS_SET_THEME":
return {
...state,
theme: {
...filter(state.theme, ["custom", "preset", "ligatures"]),
...action.theme,
},
};
case "SETTINGS_SET_THEME_OVERRIDE":
return {
...state,
theme: {
...state.theme,
custom: {
...state.theme?.custom,
...action.custom,
},
},
};
case "SETTINGS_SET_NOTIFICATION_OPTIONS":
return {
...state,
notification: {
...state.notification,
...action.options,
},
};
case "SETTINGS_SET_APPEARANCE":
return {
...state,
appearance: {
...filter(state.appearance, ["emojiPack"]),
...action.options,
},
};
case "SYNC_UPDATE":
return {
...state,
appearance: action.update.appearance?.[1] ?? state.appearance,
theme: action.update.theme?.[1] ?? state.theme,
};
case "RESET":
return {};
default:
return state;
}
}

View File

@@ -7,88 +7,88 @@ import type { AppearanceOptions } from "./settings";
export type SyncKeys = "theme" | "appearance" | "locale" | "notifications";
export interface SyncData {
locale?: Language;
theme?: ThemeOptions;
appearance?: AppearanceOptions;
notifications?: Notifications;
locale?: Language;
theme?: ThemeOptions;
appearance?: AppearanceOptions;
notifications?: Notifications;
}
export const DEFAULT_ENABLED_SYNC: SyncKeys[] = [
"theme",
"appearance",
"locale",
"notifications",
"theme",
"appearance",
"locale",
"notifications",
];
export interface SyncOptions {
disabled?: SyncKeys[];
revision?: {
[key: string]: number;
};
disabled?: SyncKeys[];
revision?: {
[key: string]: number;
};
}
export type SyncUpdateAction = {
type: "SYNC_UPDATE";
update: { [key in SyncKeys]?: [number, SyncData[key]] };
type: "SYNC_UPDATE";
update: { [key in SyncKeys]?: [number, SyncData[key]] };
};
export type SyncAction =
| { type: undefined }
| {
type: "SYNC_ENABLE_KEY";
key: SyncKeys;
}
| {
type: "SYNC_DISABLE_KEY";
key: SyncKeys;
}
| {
type: "SYNC_SET_REVISION";
key: SyncKeys;
timestamp: number;
}
| SyncUpdateAction;
| { type: undefined }
| {
type: "SYNC_ENABLE_KEY";
key: SyncKeys;
}
| {
type: "SYNC_DISABLE_KEY";
key: SyncKeys;
}
| {
type: "SYNC_SET_REVISION";
key: SyncKeys;
timestamp: number;
}
| SyncUpdateAction;
export function sync(
state = {} as SyncOptions,
action: SyncAction,
state = {} as SyncOptions,
action: SyncAction,
): SyncOptions {
switch (action.type) {
case "SYNC_DISABLE_KEY":
return {
...state,
disabled: [
...(state.disabled ?? []).filter((v) => v !== action.key),
action.key,
],
};
case "SYNC_ENABLE_KEY":
return {
...state,
disabled: state.disabled?.filter((v) => v !== action.key),
};
case "SYNC_SET_REVISION":
return {
...state,
revision: {
...state.revision,
[action.key]: action.timestamp,
},
};
case "SYNC_UPDATE": {
const revision = { ...state.revision };
for (const key of Object.keys(action.update)) {
const value = action.update[key as SyncKeys];
if (value) {
revision[key] = value[0];
}
}
switch (action.type) {
case "SYNC_DISABLE_KEY":
return {
...state,
disabled: [
...(state.disabled ?? []).filter((v) => v !== action.key),
action.key,
],
};
case "SYNC_ENABLE_KEY":
return {
...state,
disabled: state.disabled?.filter((v) => v !== action.key),
};
case "SYNC_SET_REVISION":
return {
...state,
revision: {
...state.revision,
[action.key]: action.timestamp,
},
};
case "SYNC_UPDATE": {
const revision = { ...state.revision };
for (const key of Object.keys(action.update)) {
const value = action.update[key as SyncKeys];
if (value) {
revision[key] = value[0];
}
}
return {
...state,
revision,
};
}
default:
return state;
}
return {
...state,
revision,
};
}
default:
return state;
}
}

View File

@@ -2,47 +2,47 @@ 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";
};
| { 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;
}
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;
}
}

View File

@@ -1,61 +1,61 @@
import type { Sync } from "revolt.js/dist/api/objects";
export interface Unreads {
[key: string]: Partial<Omit<Sync.ChannelUnread, "_id">>;
[key: string]: Partial<Omit<Sync.ChannelUnread, "_id">>;
}
export type UnreadsAction =
| { type: undefined }
| {
type: "UNREADS_MARK_READ";
channel: string;
message: string;
}
| {
type: "UNREADS_SET";
unreads: Sync.ChannelUnread[];
}
| {
type: "UNREADS_MENTION";
channel: string;
message: string;
}
| {
type: "RESET";
};
| { type: undefined }
| {
type: "UNREADS_MARK_READ";
channel: string;
message: string;
}
| {
type: "UNREADS_SET";
unreads: Sync.ChannelUnread[];
}
| {
type: "UNREADS_MENTION";
channel: string;
message: string;
}
| {
type: "RESET";
};
export function unreads(state = {} as Unreads, action: UnreadsAction): Unreads {
switch (action.type) {
case "UNREADS_MARK_READ":
return {
...state,
[action.channel]: {
last_id: action.message,
},
};
case "UNREADS_SET": {
const obj: Unreads = {};
for (const entry of action.unreads) {
const { _id, ...v } = entry;
obj[_id.channel] = v;
}
switch (action.type) {
case "UNREADS_MARK_READ":
return {
...state,
[action.channel]: {
last_id: action.message,
},
};
case "UNREADS_SET": {
const obj: Unreads = {};
for (const entry of action.unreads) {
const { _id, ...v } = entry;
obj[_id.channel] = v;
}
return obj;
}
case "UNREADS_MENTION": {
const obj = state[action.channel];
return obj;
}
case "UNREADS_MENTION": {
const obj = state[action.channel];
return {
...state,
[action.channel]: {
...obj,
mentions: [...(obj?.mentions ?? []), action.message],
},
};
}
case "RESET":
return {};
default:
return state;
}
return {
...state,
[action.channel]: {
...obj,
mentions: [...(obj?.mentions ?? []), action.message],
},
};
}
case "RESET":
return {};
default:
return state;
}
}