From 4d996deb1eb138c4aea9138f6198323e7661102a Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Fri, 27 May 2022 21:18:12 +0100 Subject: [PATCH] feat: add "ordering" data store --- package.json | 8 +- .../navigation/left/ServerListSidebar.tsx | 2 + src/mobx/State.ts | 4 + src/mobx/stores/Ordering.ts | 93 +++++++++++++++++++ src/mobx/stores/Sync.ts | 15 ++- yarn.lock | 24 ++--- 6 files changed, 129 insertions(+), 17 deletions(-) create mode 100644 src/mobx/stores/Ordering.ts diff --git a/package.json b/package.json index 155aa2f9..c09559e9 100644 --- a/package.json +++ b/package.json @@ -90,13 +90,13 @@ "@hcaptcha/react-hcaptcha": "^0.3.6", "@insertish/vite-plugin-babel-macros": "^1.0.5", "@preact/preset-vite": "^2.0.0", - "@revoltchat/ui": "^1.0.32", + "@revoltchat/ui": "1.0.33", "@rollup/plugin-replace": "^2.4.2", "@styled-icons/boxicons-logos": "^10.38.0", "@styled-icons/boxicons-regular": "^10.38.0", "@styled-icons/boxicons-solid": "^10.38.0", "@styled-icons/simple-icons": "^10.33.0", - "@tippyjs/react": "npm:4.2.5", + "@tippyjs/react": "4.2.6", "@traptitech/markdown-it-katex": "^3.4.3", "@traptitech/markdown-it-spoiler": "^1.1.6", "@trivago/prettier-plugin-sort-imports": "^2.0.2", @@ -138,14 +138,14 @@ "prettier": "^2.3.1", "prismjs": "^1.23.0", "react-beautiful-dnd": "^13.1.0", - "react-device-detect": "npm:2.2.2", + "react-device-detect": "2.2.2", "react-helmet": "^6.1.0", "react-hook-form": "6.3.0", "react-overlapping-panels": "1.2.2", "react-router-dom": "^5.2.0", "react-scroll": "^1.8.2", "react-virtuoso": "^2.12.0", - "revolt.js": "npm:6.0.1", + "revolt.js": "6.0.1", "rimraf": "^3.0.2", "sass": "^1.35.1", "shade-blend-color": "^1.0.0", diff --git a/src/components/navigation/left/ServerListSidebar.tsx b/src/components/navigation/left/ServerListSidebar.tsx index 57b4111d..23d2b869 100644 --- a/src/components/navigation/left/ServerListSidebar.tsx +++ b/src/components/navigation/left/ServerListSidebar.tsx @@ -35,6 +35,8 @@ export default observer(() => { createServer={createServer} permit={state.notifications} home={state.layout.getLastHomePath} + servers={state.ordering.orderedServers} + reorder={state.ordering.reorderServer} /> ); }); diff --git a/src/mobx/State.ts b/src/mobx/State.ts index a65fc561..b79461af 100644 --- a/src/mobx/State.ts +++ b/src/mobx/State.ts @@ -17,6 +17,7 @@ import Layout from "./stores/Layout"; import LocaleOptions from "./stores/LocaleOptions"; import MessageQueue from "./stores/MessageQueue"; import NotificationOptions from "./stores/NotificationOptions"; +import Ordering from "./stores/Ordering"; import Plugins from "./stores/Plugins"; import ServerConfig from "./stores/ServerConfig"; import Settings from "./stores/Settings"; @@ -41,6 +42,7 @@ export default class State { settings: Settings; sync: Sync; plugins: Plugins; + ordering: Ordering; private persistent: [string, Persistent][] = []; private disabled: Set = new Set(); @@ -62,6 +64,7 @@ export default class State { this.settings = new Settings(); this.sync = new Sync(this); this.plugins = new Plugins(this); + this.ordering = new Ordering(this); makeAutoObservable(this, { client: false, @@ -280,6 +283,7 @@ export default class State { this.queue = new MessageQueue(); this.settings = new Settings(); this.sync = new Sync(this); + this.ordering = new Ordering(this); this.save(); diff --git a/src/mobx/stores/Ordering.ts b/src/mobx/stores/Ordering.ts new file mode 100644 index 00000000..8e2ccb11 --- /dev/null +++ b/src/mobx/stores/Ordering.ts @@ -0,0 +1,93 @@ +import { action, computed, makeAutoObservable } from "mobx"; + +import { reorder } from "@revoltchat/ui"; + +import State from "../State"; +import Persistent from "../interfaces/Persistent"; +import Store from "../interfaces/Store"; +import Syncable from "../interfaces/Syncable"; + +export interface Data { + servers?: string[]; +} + +/** + * Keeps track of ordering of various elements + */ +export default class Ordering implements Store, Persistent, Syncable { + private state: State; + + /** + * Ordered list of server IDs + */ + private servers: string[]; + + /** + * Construct new Layout store. + */ + constructor(state: State) { + this.servers = []; + makeAutoObservable(this); + + this.state = state; + this.reorderServer = this.reorderServer.bind(this); + } + + get id() { + return "ordering"; + } + + toJSON() { + return { + servers: this.servers, + }; + } + + @action hydrate(data: Data) { + if (data.servers) { + this.servers = data.servers; + } + } + + apply(_key: string, data: unknown, _revision: number): void { + this.hydrate(data as Data); + } + + toSyncable(): { [key: string]: object } { + return { + ordering: this.toJSON(), + }; + } + + /** + * All known servers with ordering applied + */ + @computed get orderedServers() { + const known = new Set(this.state.client?.servers.keys() ?? []); + const ordered = [...this.servers]; + + const out = []; + for (const id of ordered) { + if (known.delete(id)) { + out.push(this.state.client!.servers.get(id)!); + } + } + + for (const id of known) { + out.push(this.state.client!.servers.get(id)!); + } + + return out; + } + + /** + * Re-order a server + */ + @action reorderServer(source: number, dest: number) { + this.servers = reorder( + this.orderedServers.map((x) => x._id), + source, + dest, + ); + } +} diff --git a/src/mobx/stores/Sync.ts b/src/mobx/stores/Sync.ts index 01acf8f4..a0d4fcfb 100644 --- a/src/mobx/stores/Sync.ts +++ b/src/mobx/stores/Sync.ts @@ -14,13 +14,19 @@ import State from "../State"; import Persistent from "../interfaces/Persistent"; import Store from "../interfaces/Store"; -export type SyncKeys = "theme" | "appearance" | "locale" | "notifications"; +export type SyncKeys = + | "theme" + | "appearance" + | "locale" + | "notifications" + | "ordering"; export const SYNC_KEYS: SyncKeys[] = [ "theme", "appearance", "locale", "notifications", + "ordering", ]; export interface Data { @@ -151,6 +157,13 @@ export default class Sync implements Store, Persistent { ); this.setRevision("notifications", notifications[0]); } + + const ordering = tryRead("ordering"); + if (ordering) { + this.state.setDisabled("ordering"); + this.state.ordering.apply("ordering", ordering[1], ordering[0]); + this.setRevision("ordering", ordering[0]); + } }); } diff --git a/yarn.lock b/yarn.lock index 92c6acdc..57906b64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2220,9 +2220,9 @@ __metadata: languageName: node linkType: hard -"@revoltchat/ui@npm:^1.0.32": - version: 1.0.32 - resolution: "@revoltchat/ui@npm:1.0.32" +"@revoltchat/ui@npm:1.0.33": + version: 1.0.33 + resolution: "@revoltchat/ui@npm:1.0.33" dependencies: "@styled-icons/boxicons-logos": ^10.38.0 "@styled-icons/boxicons-regular": ^10.38.0 @@ -2235,7 +2235,7 @@ __metadata: react-device-detect: "*" react-virtuoso: "*" revolt.js: "*" - checksum: 7004add041a66932a7efc836f33648e905bd9820dd1d65890bccc93bc95cbc643ccede67dc570341fcc9c9993fffb57702dbd6ed41dac014553be18400bc313e + checksum: 503fbf8557d205be153343776b8803335b6444b8767e0b1fccf6a34470e4cb333118f7cb614bf16e20d22cb811e7e1160622b9557b73414ad554f8b4bbfb565b languageName: node linkType: hard @@ -2384,15 +2384,15 @@ __metadata: languageName: node linkType: hard -"@tippyjs/react@npm:4.2.5": - version: 4.2.5 - resolution: "@tippyjs/react@npm:4.2.5" +"@tippyjs/react@npm:4.2.6": + version: 4.2.6 + resolution: "@tippyjs/react@npm:4.2.6" dependencies: tippy.js: ^6.3.1 peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: 68a6bb8922597df105f601953f14c593a8179328026dc425db0cd5d8521cdd8ad8c6ec7b6d0707708c8ed25e5ad01c488e95a6b3de0b2f404bd71137e2b8fce9 + checksum: 8f0fba591c9dae2e1af1ae632bbc775ba5c9dd4498e50e242be70302b4c27115c6740eec44e885e294b27cb28515777b52af5b34aac9d4bab627d948add938ae languageName: node linkType: hard @@ -3521,13 +3521,13 @@ __metadata: "@hcaptcha/react-hcaptcha": ^0.3.6 "@insertish/vite-plugin-babel-macros": ^1.0.5 "@preact/preset-vite": ^2.0.0 - "@revoltchat/ui": ^1.0.32 + "@revoltchat/ui": 1.0.33 "@rollup/plugin-replace": ^2.4.2 "@styled-icons/boxicons-logos": ^10.38.0 "@styled-icons/boxicons-regular": ^10.38.0 "@styled-icons/boxicons-solid": ^10.38.0 "@styled-icons/simple-icons": ^10.33.0 - "@tippyjs/react": "npm:4.2.5" + "@tippyjs/react": 4.2.6 "@traptitech/markdown-it-katex": ^3.4.3 "@traptitech/markdown-it-spoiler": ^1.1.6 "@trivago/prettier-plugin-sort-imports": ^2.0.2 @@ -3571,14 +3571,14 @@ __metadata: prettier: ^2.3.1 prismjs: ^1.23.0 react-beautiful-dnd: ^13.1.0 - react-device-detect: "npm:2.2.2" + react-device-detect: 2.2.2 react-helmet: ^6.1.0 react-hook-form: 6.3.0 react-overlapping-panels: 1.2.2 react-router-dom: ^5.2.0 react-scroll: ^1.8.2 react-virtuoso: ^2.12.0 - revolt.js: "npm:6.0.1" + revolt.js: 6.0.1 rimraf: ^3.0.2 sass: ^1.35.1 shade-blend-color: ^1.0.0