mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 01:23:49 +01:00
Add theme browser page accessible from game options
Removed the themes buttons that were in the ThemeEditorModal and only left a "Revert to Default" button along with a link to the ThemeBrowser page. Split off the buttons into reusable components since they are now used in two pages. Display the themes in big cards with a zoomable screenshot. Applying the theme now shows a toast with an option to undo the action. The snackbar now allows ReactNode instead of only strings. - Add link with details on how to create a new theme in the game. - Add link to the theme-sharing discord channel. - Add icons to the theme & style buttons in GameOptions - Add "Theme Editor" button to ThemeBrowser - Add "Style Editor" button to ThemeBrowser - Move Styles related files into Themes folder - Includes a modal that shows a bigger version of the screenshot. - Change Snackbar to allow for ReactNode as the message
This commit is contained in:
parent
61d6e43b37
commit
a26b9c8dcf
@ -6,7 +6,7 @@ import { GameInfo, IStyleSettings, UserInterface as IUserInterface, UserInterfac
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { ThemeEvents } from "../Themes/ui/Theme";
|
||||
import { defaultTheme } from "../Themes/Themes";
|
||||
import { defaultStyles } from "../Settings/Styles";
|
||||
import { defaultStyles } from "../Themes/Styles";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { hash } from "../hash/hash";
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ISelfInitializer, ISelfLoading } from "../types";
|
||||
import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums";
|
||||
import { defaultTheme, ITheme } from "../Themes/Themes";
|
||||
import { defaultStyles } from "./Styles";
|
||||
import { defaultStyles } from "../Themes/Styles";
|
||||
import { WordWrapOptions } from "../ScriptEditor/ui/Options";
|
||||
import { OverviewSettings } from "../ui/React/Overview";
|
||||
import { IStyleSettings } from "../ScriptEditor/NetscriptDefinitions";
|
||||
|
@ -8,7 +8,8 @@ See [CONTRIBUTING.md](/CONTRIBUTING.md) for details.
|
||||
|
||||
1. Duplicate one of the folders in `/src/Themes/data` and give it a new name (keep the hyphenated format)
|
||||
2. Modify the data in the new `/src/Themes/data/new-folder/index.ts` file
|
||||
3. Add the import/export into the `/src/Themes/data/index.ts` file
|
||||
3. Replace the screenshot.png with one of your theme
|
||||
4. Add the import/export into the `/src/Themes/data/index.ts` file
|
||||
|
||||
The themes are ordered according to the export order in `index.ts`
|
||||
|
||||
|
19
src/Themes/ui/StyleEditorButton.tsx
Normal file
19
src/Themes/ui/StyleEditorButton.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import React, { useState } from "react";
|
||||
import Button from "@mui/material/Button";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import TextFormatIcon from "@mui/icons-material/TextFormat";
|
||||
import { StyleEditorModal } from "./StyleEditorModal";
|
||||
|
||||
export function StyleEditorButton(): React.ReactElement {
|
||||
const [styleEditorOpen, setStyleEditorOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="The style editor allows you to modify certain CSS rules used by the game.">
|
||||
<Button startIcon={<TextFormatIcon />} onClick={() => setStyleEditorOpen(true)}>
|
||||
Style Editor
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<StyleEditorModal open={styleEditorOpen} onClose={() => setStyleEditorOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Modal } from "./Modal";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
@ -9,9 +9,9 @@ import TextField from "@mui/material/TextField";
|
||||
import ReplyIcon from "@mui/icons-material/Reply";
|
||||
import SaveIcon from "@mui/icons-material/Save";
|
||||
|
||||
import { ThemeEvents } from "../../Themes/ui/Theme";
|
||||
import { ThemeEvents } from "./Theme";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { defaultStyles } from "../../Settings/Styles";
|
||||
import { defaultStyles } from "../Styles";
|
||||
import { Tooltip } from "@mui/material";
|
||||
import { IStyleSettings } from "../../ScriptEditor/NetscriptDefinitions";
|
||||
|
93
src/Themes/ui/ThemeBrowser.tsx
Normal file
93
src/Themes/ui/ThemeBrowser.tsx
Normal file
@ -0,0 +1,93 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import { ThemeEvents } from "./Theme";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { getPredefinedThemes, IPredefinedTheme } from "../Themes";
|
||||
import { Box, ButtonGroup, Button } from "@mui/material";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { ThemeEditorButton } from "./ThemeEditorButton";
|
||||
import { StyleEditorButton } from "./StyleEditorButton";
|
||||
import { ThemeEntry } from "./ThemeEntry";
|
||||
import { ThemeCollaborate } from "./ThemeCollaborate";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { SnackbarEvents } from "../../ui/React/Snackbar";
|
||||
|
||||
interface IProps {
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
// Everything dies when the theme gets reloaded, so we'll keep the current scroll to not jump around.
|
||||
let previousScrollY = 0;
|
||||
|
||||
export function ThemeBrowser({ router }: IProps): React.ReactElement {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [modalImageSrc, setModalImageSrc] = useState<string | undefined>();
|
||||
const predefinedThemes = getPredefinedThemes();
|
||||
const themes = (predefinedThemes &&
|
||||
Object.entries(predefinedThemes).map(([key, templateTheme]) => (
|
||||
<ThemeEntry
|
||||
key={key}
|
||||
theme={templateTheme}
|
||||
onActivated={() => setTheme(templateTheme)}
|
||||
onImageClick={handleZoom}
|
||||
/>
|
||||
))) || <></>;
|
||||
|
||||
function setTheme(theme: IPredefinedTheme): void {
|
||||
previousScrollY = window.scrollY;
|
||||
const previousColors = { ...Settings.theme };
|
||||
Object.assign(Settings.theme, theme.colors);
|
||||
ThemeEvents.emit();
|
||||
SnackbarEvents.emit(
|
||||
<>
|
||||
Updated theme to "<strong>{theme.name}</strong>"
|
||||
<Button
|
||||
sx={{ ml: 1 }}
|
||||
color="secondary"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
Object.assign(Settings.theme, previousColors);
|
||||
ThemeEvents.emit();
|
||||
}}
|
||||
>
|
||||
UNDO
|
||||
</Button>
|
||||
</>,
|
||||
"info",
|
||||
30000,
|
||||
);
|
||||
}
|
||||
|
||||
function handleZoom(src: string): void {
|
||||
previousScrollY = window.scrollY;
|
||||
setModalImageSrc(src);
|
||||
setModalOpen(true);
|
||||
}
|
||||
|
||||
function handleCloseZoom(): void {
|
||||
previousScrollY = window.scrollY;
|
||||
setModalOpen(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
requestAnimationFrame(() => window.scrollTo(0, previousScrollY));
|
||||
});
|
||||
|
||||
return (
|
||||
<Box sx={{ mx: 2 }}>
|
||||
<Typography variant="h4">Theme Browser</Typography>
|
||||
<Paper sx={{ px: 2, py: 1, my: 1 }}>
|
||||
<ThemeCollaborate />
|
||||
<ButtonGroup sx={{ mb: 2, display: "block" }}>
|
||||
<ThemeEditorButton router={router} />
|
||||
<StyleEditorButton />
|
||||
</ButtonGroup>
|
||||
<Box sx={{ display: "flex", flexWrap: "wrap" }}>{themes}</Box>
|
||||
<Modal open={modalOpen} onClose={handleCloseZoom}>
|
||||
<img src={modalImageSrc} style={{ width: "100%" }} />
|
||||
</Modal>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
24
src/Themes/ui/ThemeCollaborate.tsx
Normal file
24
src/Themes/ui/ThemeCollaborate.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Link } from "@mui/material";
|
||||
|
||||
export function ThemeCollaborate(): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<Typography sx={{ my: 1 }}>
|
||||
If you've created a theme that you believe should be added in game's theme browser, feel free to{" "}
|
||||
<Link href="https://github.com/danielyxie/bitburner/tree/dev/src/Themes/README.md" target="_blank">
|
||||
create a pull request
|
||||
</Link>
|
||||
.
|
||||
</Typography>
|
||||
<Typography sx={{ my: 1 }}>
|
||||
Head over to the{" "}
|
||||
<Link href="https://discord.com/channels/415207508303544321/921991895230611466" target="_blank">
|
||||
theme-sharing
|
||||
</Link>{" "}
|
||||
discord channel for more.
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
24
src/Themes/ui/ThemeEditorButton.tsx
Normal file
24
src/Themes/ui/ThemeEditorButton.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React, { useState } from "react";
|
||||
import Button from "@mui/material/Button";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import { ThemeEditorModal } from "./ThemeEditorModal";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import ColorizeIcon from "@mui/icons-material/Colorize";
|
||||
|
||||
interface IProps {
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export function ThemeEditorButton({ router }: IProps): React.ReactElement {
|
||||
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="The theme editor allows you to modify the colors the game uses.">
|
||||
<Button startIcon={<ColorizeIcon />} onClick={() => setThemeEditorOpen(true)}>
|
||||
Theme Editor
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<ThemeEditorModal open={themeEditorOpen} onClose={() => setThemeEditorOpen(false)} router={router} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import Button from "@mui/material/Button";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Paper from "@mui/material/Paper";
|
||||
@ -8,15 +9,19 @@ import TextField from "@mui/material/TextField";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import ReplyIcon from "@mui/icons-material/Reply";
|
||||
import PaletteSharpIcon from "@mui/icons-material/PaletteSharp";
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import { Color, ColorPicker } from "material-ui-color";
|
||||
import { ThemeEvents } from "./Theme";
|
||||
import { Settings, defaultSettings } from "../../Settings/Settings";
|
||||
import { getPredefinedThemes } from "../Themes";
|
||||
import { defaultTheme } from "../Themes";
|
||||
import { UserInterfaceTheme } from "../../ScriptEditor/NetscriptDefinitions";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
import { ThemeCollaborate } from "./ThemeCollaborate";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
interface IColorEditorProps {
|
||||
@ -68,28 +73,6 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
...Settings.theme,
|
||||
});
|
||||
|
||||
const predefinedThemes = getPredefinedThemes();
|
||||
const themes = predefinedThemes && Object.entries(predefinedThemes)
|
||||
.map(([key, templateTheme]) => {
|
||||
const name = templateTheme.name || key;
|
||||
let inner = <Typography>{name}</Typography>;
|
||||
let toolTipTitle;
|
||||
if (templateTheme.credit) {
|
||||
toolTipTitle = <Typography>{templateTheme.description || name} <em>by {templateTheme.credit}</em></Typography>;
|
||||
} else if (templateTheme.description) {
|
||||
toolTipTitle = <Typography>{templateTheme.description}</Typography>;
|
||||
}
|
||||
if (toolTipTitle) {
|
||||
inner = <Tooltip title={toolTipTitle}>{inner}</Tooltip>
|
||||
}
|
||||
return (
|
||||
<Button onClick={() => setTemplateTheme(templateTheme.colors)}
|
||||
startIcon={<PaletteSharpIcon />} key={key} sx={{ mr: 1, mb: 1 }}>
|
||||
{inner}
|
||||
</Button>
|
||||
);
|
||||
}) || <></>;
|
||||
|
||||
function setTheme(theme: UserInterfaceTheme): void {
|
||||
setCustomTheme(theme);
|
||||
Object.assign(Settings.theme, theme);
|
||||
@ -372,8 +355,18 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
/>
|
||||
<>
|
||||
<Typography sx={{ my: 1 }}>Backup your theme or share it with others by copying the string above.</Typography>
|
||||
<Typography sx={{ my: 1 }}>Replace the current theme with a pre-built template using the buttons below.</Typography>
|
||||
{themes}
|
||||
<ThemeCollaborate />
|
||||
<ButtonGroup>
|
||||
<Tooltip title="Reverts all modification back to the default theme. This is permanent.">
|
||||
<Button onClick={() => setTemplateTheme(defaultTheme)}
|
||||
startIcon={<HistoryIcon />}>
|
||||
Revert to Default
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Move over to the theme browser's page to use one of our predefined themes.">
|
||||
<Button startIcon={<PaletteSharpIcon />} onClick={() => props.router.toThemeBrowser()}>See more themes</Button>
|
||||
</Tooltip>
|
||||
</ButtonGroup>
|
||||
</>
|
||||
</Paper>
|
||||
</Modal>
|
||||
|
77
src/Themes/ui/ThemeEntry.tsx
Normal file
77
src/Themes/ui/ThemeEntry.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
import React from "react";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import PaletteSharpIcon from "@mui/icons-material/PaletteSharp";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { IPredefinedTheme } from "../Themes";
|
||||
import { Link, Card, CardHeader, CardContent, CardMedia, Button } from "@mui/material";
|
||||
|
||||
interface IProps {
|
||||
theme: IPredefinedTheme;
|
||||
onActivated: () => void;
|
||||
onImageClick: (src: string) => void;
|
||||
}
|
||||
|
||||
export function ThemeEntry({ theme, onActivated, onImageClick }: IProps): React.ReactElement {
|
||||
if (!theme) return <></>;
|
||||
return (
|
||||
<Card key={theme.screenshot} sx={{ width: 400, mr: 1, mb: 1 }}>
|
||||
<CardHeader
|
||||
action={
|
||||
<Tooltip title="Use this theme">
|
||||
<Button startIcon={<PaletteSharpIcon />} onClick={onActivated} variant="outlined">
|
||||
Use
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
title={theme.name}
|
||||
subheader={
|
||||
<>
|
||||
by {theme.credit}{" "}
|
||||
{theme.reference && (
|
||||
<>
|
||||
(
|
||||
<Link href={theme.reference} target="_blank">
|
||||
ref
|
||||
</Link>
|
||||
)
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
sx={{
|
||||
color: Settings.theme.primary,
|
||||
"& .MuiCardHeader-subheader": {
|
||||
color: Settings.theme.secondarydark,
|
||||
},
|
||||
"& .MuiButton-outlined": {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<CardMedia
|
||||
component="img"
|
||||
width="400"
|
||||
image={theme.screenshot}
|
||||
alt={`Theme Screenshot of "${theme.name}"`}
|
||||
sx={{
|
||||
borderTop: `1px solid ${Settings.theme.welllight}`,
|
||||
borderBottom: `1px solid ${Settings.theme.welllight}`,
|
||||
cursor: "zoom-in",
|
||||
}}
|
||||
onClick={() => onImageClick(theme.screenshot)}
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
color: Settings.theme.primarydark,
|
||||
}}
|
||||
>
|
||||
{theme.description}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -79,6 +79,7 @@ import { RecoveryMode, RecoveryRoot } from "./React/RecoveryRoot";
|
||||
import { AchievementsRoot } from "../Achievements/AchievementsRoot";
|
||||
import { ErrorBoundary } from "./ErrorBoundary";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { ThemeBrowser } from "../Themes/ui/ThemeBrowser";
|
||||
|
||||
const htmlLocation = location;
|
||||
|
||||
@ -194,6 +195,9 @@ export let Router: IRouter = {
|
||||
toAchievements: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toThemeBrowser: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
};
|
||||
|
||||
function determineStartPage(player: IPlayer): Page {
|
||||
@ -307,6 +311,9 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
toAchievements: () => {
|
||||
setPage(Page.Achievements);
|
||||
},
|
||||
toThemeBrowser: () => {
|
||||
setPage(Page.ThemeBrowser);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -471,6 +478,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
mainPage = (
|
||||
<GameOptionsRoot
|
||||
player={player}
|
||||
router={Router}
|
||||
save={() => saveObject.saveGame()}
|
||||
export={() => {
|
||||
// Apply the export bonus before saving the game
|
||||
@ -503,6 +511,10 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
|
||||
mainPage = <AchievementsRoot />;
|
||||
break;
|
||||
}
|
||||
case Page.ThemeBrowser: {
|
||||
mainPage = <ThemeBrowser router={Router} />;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -22,12 +22,11 @@ import TextField from "@mui/material/TextField";
|
||||
import DownloadIcon from "@mui/icons-material/Download";
|
||||
import UploadIcon from "@mui/icons-material/Upload";
|
||||
import SaveIcon from "@mui/icons-material/Save";
|
||||
import PaletteIcon from '@mui/icons-material/Palette';
|
||||
|
||||
import { FileDiagnosticModal } from "../../Diagnostic/FileDiagnosticModal";
|
||||
import { dialogBoxCreate } from "./DialogBox";
|
||||
import { ConfirmationModal } from "./ConfirmationModal";
|
||||
import { ThemeEditorModal } from "../../Themes/ui/ThemeEditorModal";
|
||||
import { StyleEditorModal } from "./StyleEditorModal";
|
||||
|
||||
import { SnackbarEvents } from "./Snackbar";
|
||||
|
||||
@ -37,6 +36,9 @@ import { formatTime } from "../../utils/helpers/formatTime";
|
||||
import { OptionSwitch } from "./OptionSwitch";
|
||||
import { DeleteGameButton } from "./DeleteGameButton";
|
||||
import { SoftResetButton } from "./SoftResetButton";
|
||||
import { IRouter } from "../Router";
|
||||
import { ThemeEditorButton } from "../../Themes/ui/ThemeEditorButton";
|
||||
import { StyleEditorButton } from "../../Themes/ui/StyleEditorButton";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@ -50,6 +52,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
router: IRouter;
|
||||
save: () => void;
|
||||
export: () => void;
|
||||
forceKill: () => void;
|
||||
@ -74,8 +77,6 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
||||
const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat);
|
||||
const [locale, setLocale] = useState(Settings.Locale);
|
||||
const [diagnosticOpen, setDiagnosticOpen] = useState(false);
|
||||
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
|
||||
const [styleEditorOpen, setStyleEditorOpen] = useState(false);
|
||||
const [importSaveOpen, setImportSaveOpen] = useState(false);
|
||||
const [importData, setImportData] = useState<ImportData | null>(null);
|
||||
|
||||
@ -642,9 +643,14 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
||||
<Button onClick={() => setDiagnosticOpen(true)}>Diagnose files</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
|
||||
<Button onClick={() => setThemeEditorOpen(true)}>Theme editor</Button>
|
||||
<Button onClick={() => setStyleEditorOpen(true)}>Style editor</Button>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr" }}>
|
||||
<Tooltip title="Head to the theme browser to see a collection of prebuilt themes.">
|
||||
<Button startIcon={<PaletteIcon />} onClick={() => props.router.toThemeBrowser()}>
|
||||
Theme Browser
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<ThemeEditorButton router={props.router} />
|
||||
<StyleEditorButton />
|
||||
</Box>
|
||||
<Box>
|
||||
<Link href="https://github.com/danielyxie/bitburner/issues/new" target="_blank">
|
||||
@ -669,8 +675,6 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
|
||||
</Box>
|
||||
</Grid>
|
||||
<FileDiagnosticModal open={diagnosticOpen} onClose={() => setDiagnosticOpen(false)} />
|
||||
<ThemeEditorModal open={themeEditorOpen} onClose={() => setThemeEditorOpen(false)} />
|
||||
<StyleEditorModal open={styleEditorOpen} onClose={() => setStyleEditorOpen(false)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -14,6 +14,10 @@ const useStyles = makeStyles(() => ({
|
||||
snackbar: {
|
||||
// Log popup z-index increments, so let's add a padding to be well above them.
|
||||
zIndex: `${logBoxBaseZIndex + 1000} !important` as any,
|
||||
|
||||
"& .MuiAlert-icon": {
|
||||
alignSelf: 'center',
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
@ -27,7 +31,7 @@ export function SnackbarProvider(props: IProps): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
export const SnackbarEvents = new EventEmitter<[string, "success" | "warning" | "error" | "info", number]>();
|
||||
export const SnackbarEvents = new EventEmitter<[string | React.ReactNode, "success" | "warning" | "error" | "info", number]>();
|
||||
|
||||
export function Snackbar(): React.ReactElement {
|
||||
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
|
||||
|
@ -37,6 +37,7 @@ export enum Page {
|
||||
StaneksGift,
|
||||
Recovery,
|
||||
Achievements,
|
||||
ThemeBrowser,
|
||||
}
|
||||
|
||||
export interface ScriptEditorRouteOptions {
|
||||
@ -82,4 +83,5 @@ export interface IRouter {
|
||||
toLocation(location: Location): void;
|
||||
toStaneksGift(): void;
|
||||
toAchievements(): void;
|
||||
toThemeBrowser(): void;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user