86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|
|
|
interface Notification {
|
|
id: string;
|
|
message: string;
|
|
type: "info" | "success" | "error" | "warning";
|
|
}
|
|
|
|
interface UiState {
|
|
theme: "light" | "dark";
|
|
accentColor: string;
|
|
notifications: Notification[];
|
|
isMobileSidebarOpen: boolean;
|
|
isPreviewMode: boolean;
|
|
}
|
|
|
|
const getInitialTheme = (): "light" | "dark" => {
|
|
const saved = localStorage.getItem("theme");
|
|
if (saved === "dark" || saved === "light") return saved;
|
|
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
? "dark"
|
|
: "light";
|
|
};
|
|
|
|
const initialState: UiState = {
|
|
theme: getInitialTheme(),
|
|
accentColor: localStorage.getItem("accentColor") || "#007bff",
|
|
notifications: [],
|
|
isMobileSidebarOpen: false,
|
|
isPreviewMode: false,
|
|
};
|
|
|
|
const uiSlice = createSlice({
|
|
name: "ui",
|
|
initialState,
|
|
reducers: {
|
|
toggleTheme: (state) => {
|
|
state.theme = state.theme === "light" ? "dark" : "light";
|
|
localStorage.setItem("theme", state.theme);
|
|
},
|
|
setTheme: (state, action: PayloadAction<"light" | "dark">) => {
|
|
state.theme = action.payload;
|
|
localStorage.setItem("theme", state.theme);
|
|
},
|
|
setAccentColor: (state, action: PayloadAction<string>) => {
|
|
state.accentColor = action.payload;
|
|
localStorage.setItem("accentColor", action.payload);
|
|
},
|
|
addNotification: (
|
|
state,
|
|
action: PayloadAction<Omit<Notification, "id">>
|
|
) => {
|
|
const id = `notification-${Date.now()}-${Math.random()
|
|
.toString(36)
|
|
.substr(2, 9)}`;
|
|
state.notifications.push({ ...action.payload, id });
|
|
},
|
|
removeNotification: (state, action: PayloadAction<string>) => {
|
|
state.notifications = state.notifications.filter(
|
|
(n) => n.id !== action.payload
|
|
);
|
|
},
|
|
toggleMobileSidebar: (state) => {
|
|
state.isMobileSidebarOpen = !state.isMobileSidebarOpen;
|
|
},
|
|
closeMobileSidebar: (state) => {
|
|
state.isMobileSidebarOpen = false;
|
|
},
|
|
togglePreviewMode: (state) => {
|
|
state.isPreviewMode = !state.isPreviewMode;
|
|
},
|
|
},
|
|
});
|
|
|
|
export const {
|
|
toggleTheme,
|
|
setTheme,
|
|
setAccentColor,
|
|
addNotification,
|
|
removeNotification,
|
|
toggleMobileSidebar,
|
|
closeMobileSidebar,
|
|
togglePreviewMode,
|
|
} = uiSlice.actions;
|
|
export default uiSlice.reducer;
|