mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-09 16:53:36 -05:00
feat(mobx): start work on migrations
This commit is contained in:
parent
89dda8fe82
commit
68578d2620
8 changed files with 105 additions and 99 deletions
|
@ -34,7 +34,13 @@ import { ThemeBaseSelector } from "./appearance/ThemeBaseSelector";
|
||||||
export const ThemeBaseSelectorShim = observer(() => {
|
export const ThemeBaseSelectorShim = observer(() => {
|
||||||
const theme = useApplicationState().settings.theme;
|
const theme = useApplicationState().settings.theme;
|
||||||
return (
|
return (
|
||||||
<ThemeBaseSelector value={theme.getBase()} setValue={theme.setBase} />
|
<ThemeBaseSelector
|
||||||
|
value={theme.isModified() ? undefined : theme.getBase()}
|
||||||
|
setValue={(base) => {
|
||||||
|
theme.setBase(base);
|
||||||
|
theme.reset();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -97,10 +103,6 @@ export const ThemeCustomCSSShim = observer(() => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ThemeImporterShim = observer(() => {
|
|
||||||
return <a></a>;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component providing a way to switch between compact and normal message view.
|
* Component providing a way to switch between compact and normal message view.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -92,7 +92,7 @@ export function EmojiSelector({ value, setValue }: Props) {
|
||||||
<div
|
<div
|
||||||
class="button"
|
class="button"
|
||||||
onClick={() => setValue("mutant")}
|
onClick={() => setValue("mutant")}
|
||||||
data-active={value === "mutant"}>
|
data-active={!value || value === "mutant"}>
|
||||||
<img
|
<img
|
||||||
loading="eager"
|
loading="eager"
|
||||||
src={mutantSVG}
|
src={mutantSVG}
|
||||||
|
|
11
src/mobx/interfaces/Migrate.ts
Normal file
11
src/mobx/interfaces/Migrate.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import Store from "./Store";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data store which is migrated forwards.
|
||||||
|
*/
|
||||||
|
export default interface Migrate<K extends string> extends Store {
|
||||||
|
/**
|
||||||
|
* Migrate this data store.
|
||||||
|
*/
|
||||||
|
migrate(key: K, data: Record<string, unknown>, rev: number): void;
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
|
||||||
|
|
||||||
import { mapToRecord } from "../../lib/conversion";
|
|
||||||
|
|
||||||
import { StoredTheme } from "../../redux/reducers/themes";
|
|
||||||
|
|
||||||
import Persistent from "../interfaces/Persistent";
|
|
||||||
import Store from "../interfaces/Store";
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
themes: Record<string, StoredTheme>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache data store for temporary, long-lived data.
|
|
||||||
*/
|
|
||||||
export default class Cache implements Store, Persistent<Data> {
|
|
||||||
private themes: ObservableMap<string, StoredTheme>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct new Cache store.
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
this.themes = new ObservableMap();
|
|
||||||
makeAutoObservable(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
get id() {
|
|
||||||
return "draft";
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON() {
|
|
||||||
return {
|
|
||||||
themes: JSON.parse(JSON.stringify(mapToRecord(this.themes))),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@action hydrate(data: Data) {
|
|
||||||
Object.keys(data.themes).forEach((key) =>
|
|
||||||
this.themes.set(key, data.themes[key]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache a given theme.
|
|
||||||
* @param theme Theme
|
|
||||||
*/
|
|
||||||
@action cacheTheme(theme: StoredTheme) {
|
|
||||||
this.themes.set(theme.slug, theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a cached theme.
|
|
||||||
* @param slug String
|
|
||||||
*/
|
|
||||||
@action removeTheme(slug: string) {
|
|
||||||
this.themes.delete(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a cached theme by its slug.
|
|
||||||
* @param slug Theme slug
|
|
||||||
* @returns Theme, if found
|
|
||||||
*/
|
|
||||||
@computed getTheme(slug: string) {
|
|
||||||
return this.themes.get(slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all cached themes.
|
|
||||||
* @returns Themes
|
|
||||||
*/
|
|
||||||
@computed getThemes() {
|
|
||||||
return [...this.themes.values()];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -50,7 +50,6 @@ export default class Experiments implements Store, Persistent<Data> {
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.enabled = new ObservableSet();
|
this.enabled = new ObservableSet();
|
||||||
|
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
70
src/mobx/stores/Sync.ts
Normal file
70
src/mobx/stores/Sync.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import {
|
||||||
|
action,
|
||||||
|
computed,
|
||||||
|
makeAutoObservable,
|
||||||
|
ObservableMap,
|
||||||
|
ObservableSet,
|
||||||
|
} from "mobx";
|
||||||
|
import { Client } from "revolt.js";
|
||||||
|
|
||||||
|
import { mapToRecord } from "../../lib/conversion";
|
||||||
|
|
||||||
|
import Persistent from "../interfaces/Persistent";
|
||||||
|
import Store from "../interfaces/Store";
|
||||||
|
|
||||||
|
export type SyncKeys = "theme" | "appearance" | "locale" | "notifications";
|
||||||
|
|
||||||
|
export const SYNC_KEYS: SyncKeys[] = [
|
||||||
|
"theme",
|
||||||
|
"appearance",
|
||||||
|
"locale",
|
||||||
|
"notifications",
|
||||||
|
];
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
disabled: SyncKeys[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles syncing settings data.
|
||||||
|
*/
|
||||||
|
export default class Sync implements Store, Persistent<Data> {
|
||||||
|
private disabled: ObservableSet<SyncKeys>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct new Sync store.
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.disabled = new ObservableSet();
|
||||||
|
makeAutoObservable(this);
|
||||||
|
this.isEnabled = this.isEnabled.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return "sync";
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
enabled: [...this.disabled],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@action hydrate(data: Data) {
|
||||||
|
if (data.disabled) {
|
||||||
|
for (const key of data.disabled) {
|
||||||
|
this.disabled.add(key as SyncKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed isEnabled(key: SyncKeys) {
|
||||||
|
return !this.disabled.has(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
async pull(client: Client) {
|
||||||
|
const data = await client.syncFetchSettings(
|
||||||
|
SYNC_KEYS.filter(this.isEnabled),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,9 @@ export default class STheme {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action hydrate(data: Partial<Theme>) {
|
@action hydrate(data: Partial<Theme>, resetCSS = false) {
|
||||||
|
if (resetCSS) this.setCSS();
|
||||||
|
|
||||||
for (const key of Object.keys(data)) {
|
for (const key of Object.keys(data)) {
|
||||||
const value = data[key as keyof Theme] as string;
|
const value = data[key as keyof Theme] as string;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
@ -137,8 +139,8 @@ export default class STheme {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action setCSS(value: string) {
|
@action setCSS(value?: string) {
|
||||||
if (value.length > 0) {
|
if (value && value.length > 0) {
|
||||||
this.settings.set("appearance:theme:css", value);
|
this.settings.set("appearance:theme:css", value);
|
||||||
} else {
|
} else {
|
||||||
this.settings.remove("appearance:theme:css");
|
this.settings.remove("appearance:theme:css");
|
||||||
|
@ -153,6 +155,13 @@ export default class STheme {
|
||||||
return this.settings.get("appearance:theme:css");
|
return this.settings.get("appearance:theme:css");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@computed isModified() {
|
||||||
|
return (
|
||||||
|
Object.keys(this.settings.get("appearance:theme:overrides") ?? {})
|
||||||
|
.length > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@action setBase(base?: "light" | "dark") {
|
@action setBase(base?: "light" | "dark") {
|
||||||
if (base) {
|
if (base) {
|
||||||
this.settings.set("appearance:theme:base", base);
|
this.settings.set("appearance:theme:base", base);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import styled from "styled-components";
|
||||||
|
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
import { useApplicationState } from "../../../mobx/State";
|
||||||
import { dispatch } from "../../../redux";
|
import { dispatch } from "../../../redux";
|
||||||
|
|
||||||
import { Theme, generateVariables, ThemeOptions } from "../../../context/Theme";
|
import { Theme, generateVariables, ThemeOptions } from "../../../context/Theme";
|
||||||
|
@ -149,6 +150,8 @@ export function ThemeShop() {
|
||||||
>(null);
|
>(null);
|
||||||
const [themeData, setThemeData] = useState<Record<string, Theme>>({});
|
const [themeData, setThemeData] = useState<Record<string, Theme>>({});
|
||||||
|
|
||||||
|
const themes = useApplicationState().settings.theme;
|
||||||
|
|
||||||
async function fetchThemeList() {
|
async function fetchThemeList() {
|
||||||
const manifest = await fetchManifest();
|
const manifest = await fetchManifest();
|
||||||
setThemeList(
|
setThemeList(
|
||||||
|
@ -190,19 +193,7 @@ export function ThemeShop() {
|
||||||
<button
|
<button
|
||||||
class="preview"
|
class="preview"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dispatch({
|
themes.hydrate(themeData[slug], true);
|
||||||
type: "THEMES_SET_THEME",
|
|
||||||
theme: {
|
|
||||||
slug,
|
|
||||||
meta: theme,
|
|
||||||
theme: themeData[slug]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: "SETTINGS_SET_THEME",
|
|
||||||
theme: { base: slug },
|
|
||||||
});
|
|
||||||
}}>
|
}}>
|
||||||
<ThemePreview slug={slug} theme={themeData[slug]} />
|
<ThemePreview slug={slug} theme={themeData[slug]} />
|
||||||
</button>
|
</button>
|
||||||
|
|
Loading…
Reference in a new issue