mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
enhancement(web): add react suspense and improve DX (#1089)
* add react suspense, fix broken stuff, clean up code, improve DX enhancement: added react suspense + spinner to show loading (still can be added in certain places) chore: cleaned up Header/NavBar code chore: cleaned up DeleteModal code chore: cleaned up other relevant code enhancement: changed remove button style to be much more pleasant (see e.g. filter tabs) fix: made active tab on filters page to be blue (as it should've been) when active fix: fixed ghost delimiter which was only visible when DeleteModal was active in FormButtonGroup chore: removed most of linter warnings/errors fix: fixed incorrect/double modal transition in FilterExternalItem fix: fixed incorrect z-height on Options popover in Settings/IRC (would've been visible when Add new was clicked) enhancement: improved robustness of all Context classes to support seamless new-feature expansion (#866) enhancement: improved expand logic (see #994 comments) * reverted irc expand view to previous design * forgot to propagate previous z-height fix * jinxed it * add license header to new files --------- Co-authored-by: martylukyy <35452459+martylukyy@users.noreply.github.com> Co-authored-by: Kyle Sanderson <kyle.leet@gmail.com>
This commit is contained in:
parent
cbf668e87c
commit
2fed48e0dd
23 changed files with 845 additions and 737 deletions
|
@ -4,53 +4,13 @@
|
|||
*/
|
||||
|
||||
import { newRidgeState } from "react-ridge-state";
|
||||
|
||||
export const InitializeGlobalContext = () => {
|
||||
const auth_ctx = localStorage.getItem("auth");
|
||||
if (auth_ctx)
|
||||
AuthContext.set(JSON.parse(auth_ctx));
|
||||
|
||||
const settings_ctx = localStorage.getItem("settings");
|
||||
if (settings_ctx) {
|
||||
SettingsContext.set(JSON.parse(settings_ctx));
|
||||
} else {
|
||||
// Only check for light theme, otherwise dark theme is the default
|
||||
SettingsContext.set((state) => ({
|
||||
...state,
|
||||
darkTheme: !(
|
||||
window.matchMedia !== undefined &&
|
||||
window.matchMedia("(prefers-color-scheme: light)").matches
|
||||
)
|
||||
}));
|
||||
}
|
||||
const filterList_ctx = localStorage.getItem("filterList");
|
||||
if (filterList_ctx) {
|
||||
FilterListContext.set(JSON.parse(filterList_ctx));
|
||||
}
|
||||
};
|
||||
import type { StateWithValue } from "react-ridge-state";
|
||||
|
||||
interface AuthInfo {
|
||||
username: string;
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
export const AuthContext = newRidgeState<AuthInfo>(
|
||||
{
|
||||
username: "",
|
||||
isLoggedIn: false
|
||||
},
|
||||
{
|
||||
onSet: (new_state) => {
|
||||
try {
|
||||
localStorage.setItem("auth", JSON.stringify(new_state));
|
||||
} catch (e) {
|
||||
console.log("An error occurred while trying to modify the local auth context state.");
|
||||
console.log("Error:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
interface SettingsType {
|
||||
debug: boolean;
|
||||
checkForUpdates: boolean;
|
||||
|
@ -60,83 +20,111 @@ interface SettingsType {
|
|||
hideWrappedText: boolean;
|
||||
}
|
||||
|
||||
export const SettingsContext = newRidgeState<SettingsType>(
|
||||
{
|
||||
debug: false,
|
||||
checkForUpdates: true,
|
||||
darkTheme: true,
|
||||
scrollOnNewLog: false,
|
||||
indentLogLines: false,
|
||||
hideWrappedText: false
|
||||
},
|
||||
{
|
||||
onSet: (new_state) => {
|
||||
try {
|
||||
document.documentElement.classList.toggle("dark", new_state.darkTheme);
|
||||
localStorage.setItem("settings", JSON.stringify(new_state));
|
||||
} catch (e) {
|
||||
console.log("An error occurred while trying to modify the local settings context state.");
|
||||
console.log("Error:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export type FilterListState = {
|
||||
indexerFilter: string[],
|
||||
indexerFilter: string[];
|
||||
sortOrder: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
// Default values
|
||||
const AuthContextDefaults: AuthInfo = {
|
||||
username: "",
|
||||
isLoggedIn: false
|
||||
};
|
||||
|
||||
const SettingsContextDefaults: SettingsType = {
|
||||
debug: false,
|
||||
checkForUpdates: true,
|
||||
darkTheme: true,
|
||||
scrollOnNewLog: false,
|
||||
indentLogLines: false,
|
||||
hideWrappedText: false
|
||||
};
|
||||
|
||||
const FilterListContextDefaults: FilterListState = {
|
||||
indexerFilter: [],
|
||||
sortOrder: "",
|
||||
status: ""
|
||||
};
|
||||
|
||||
// eslint-disable-next-line
|
||||
function ContextMerger<T extends {}>(
|
||||
key: string,
|
||||
defaults: T,
|
||||
ctxState: StateWithValue<T>
|
||||
) {
|
||||
const storage = localStorage.getItem(key);
|
||||
if (!storage) {
|
||||
// Nothing to do. We already have a value thanks to react-ridge-state.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const json = JSON.parse(storage);
|
||||
if (json === null) {
|
||||
console.warn(`JSON localStorage value for '${key}' context state is null`);
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(defaults).forEach((key) => {
|
||||
const propName = key as unknown as keyof T;
|
||||
|
||||
// Check if JSON in localStorage is missing newly added key
|
||||
if (!Object.prototype.hasOwnProperty.call(json, key)) {
|
||||
// ... and default-initialize it.
|
||||
json[propName] = defaults[propName];
|
||||
}
|
||||
});
|
||||
|
||||
ctxState.set(json);
|
||||
} catch (e) {
|
||||
console.error(`Failed to merge ${key} context state: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const InitializeGlobalContext = () => {
|
||||
ContextMerger<AuthInfo>("auth", AuthContextDefaults, AuthContext);
|
||||
ContextMerger<SettingsType>(
|
||||
"settings",
|
||||
SettingsContextDefaults,
|
||||
SettingsContext
|
||||
);
|
||||
ContextMerger<FilterListState>(
|
||||
"filterList",
|
||||
FilterListContextDefaults,
|
||||
FilterListContext
|
||||
);
|
||||
};
|
||||
|
||||
function DefaultSetter<T>(name: string, newState: T, prevState: T) {
|
||||
try {
|
||||
localStorage.setItem(name, JSON.stringify(newState));
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`An error occurred while trying to modify '${name}' context state: ${e}`
|
||||
);
|
||||
console.warn(` --> prevState: ${prevState}`);
|
||||
console.warn(` --> newState: ${newState}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const AuthContext = newRidgeState<AuthInfo>(AuthContextDefaults, {
|
||||
onSet: (newState, prevState) => DefaultSetter("auth", newState, prevState)
|
||||
});
|
||||
|
||||
export const SettingsContext = newRidgeState<SettingsType>(
|
||||
SettingsContextDefaults,
|
||||
{
|
||||
onSet: (newState, prevState) => {
|
||||
document.documentElement.classList.toggle("dark", newState.darkTheme);
|
||||
DefaultSetter("settings", newState, prevState);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const FilterListContext = newRidgeState<FilterListState>(
|
||||
FilterListContextDefaults,
|
||||
{
|
||||
indexerFilter: [],
|
||||
sortOrder: "",
|
||||
status: ""
|
||||
},
|
||||
{
|
||||
onSet: (new_state) => {
|
||||
try {
|
||||
localStorage.setItem("filterList", JSON.stringify(new_state));
|
||||
} catch (e) {
|
||||
console.log("An error occurred while trying to modify the local filter list context state.");
|
||||
console.log("Error:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export type IrcNetworkState = {
|
||||
id: number;
|
||||
name: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type IrcBufferType = "NICK" | "CHANNEL" | "SERVER";
|
||||
|
||||
export type IrcBufferState = {
|
||||
id: number;
|
||||
name: string;
|
||||
type: IrcBufferType;
|
||||
messages: string[];
|
||||
};
|
||||
|
||||
export type IrcState = {
|
||||
networks: Map<string, IrcNetworkState>;
|
||||
buffers: Map<string, IrcBufferState>
|
||||
};
|
||||
export const IrcContext = newRidgeState<IrcState>(
|
||||
{
|
||||
networks: new Map(),
|
||||
buffers: new Map()
|
||||
},
|
||||
{
|
||||
onSet: (new_state) => {
|
||||
try {
|
||||
console.log("set irc state", new_state);
|
||||
} catch (e) {
|
||||
console.log("Error:", e);
|
||||
}
|
||||
}
|
||||
onSet: (newState, prevState) => DefaultSetter("filterList", newState, prevState)
|
||||
}
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue