UI: Add a Credits button in options menu (#836)

This commit is contained in:
missymae#2783 2023-10-02 18:00:52 -06:00 committed by GitHub
parent a8e48ddb12
commit 3c52984d61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 117 additions and 9 deletions

@ -0,0 +1,89 @@
import React from "react";
import { Modal } from "../../ui/React/Modal";
import { Typography, Link, Button } from "@mui/material";
import { CONSTANTS } from "../../Constants";
interface CreditsModalProps {
open: boolean;
onClose: () => void;
}
const enclosed = /(\([^)]+\))/gm; //grab all filled () pairs
const recentPatchData = Array.from(new Set(CONSTANTS.LatestUpdate.match(enclosed)));
const isDate = (data: string) => {
const regex = /^\(last update/gm; //(this) isn't @name, but may be useful
return regex.test(data);
};
const updateMessage = []; //store last update message, eg (last updated 9/12/23)
if (isDate(recentPatchData[0])) updateMessage.push(recentPatchData[0]);
const handle: string[] = [];
for (let i = 0; i < recentPatchData.length; i++) {
const atName = /(?:^[(]?(@[^\s),]+)[),]?)/gm; //make an array of only unique @handles
const whatWeWant = recentPatchData[i].replace(atName, "$1");
if (isDate(recentPatchData[i]) || !recentPatchData[i].includes("@")) continue;
if (recentPatchData[i].includes(", ")) {
//if (@1, @2, ...@n)
recentPatchData.push(...recentPatchData[i].split(", "));
continue;
}
if (!handle.includes(whatWeWant)) handle.push(whatWeWant);
}
export function CreditsModal(props: CreditsModalProps): React.ReactElement {
const leadDevs = `danielyxie
Olivier Gagnon
@Snarling
`;
const currentMaintainer = `@Snarling`;
const handles = handle.sort((a, b) => a.localeCompare(b)).join(", ");
const contributorsURL = `https://github.com/bitburner-official/bitburner-src/graphs/contributors`;
const contributorsMessage = `Visit GitHub to see all contributors
or to participate yourself`;
const maxEM = Math.floor(contributorsMessage.length / 2);
return (
<Modal
open={props.open}
onClose={props.onClose}
sx={{
textAlign: "center",
}}
>
<Typography alignContent={"start"} variant="h3">
Bitburner
</Typography>
<Typography sx={{ textDecoration: "underline" }}>Original Code and Concept</Typography>
<Typography>danielyxie</Typography>
<br />
<Typography sx={{ textDecoration: "underline" }}>Lead Developers:</Typography>
<Typography style={{ whiteSpace: "pre-wrap" }}>{leadDevs}</Typography>
<br />
<Typography sx={{ textDecoration: "underline" }}>Current Maintainer</Typography>
<Typography>{currentMaintainer}</Typography>
<br />
<Typography sx={{ textDecoration: "underline" }}>Recent patch contributors:</Typography>
<Typography style={{ whiteSpace: "pre-wrap", maxWidth: maxEM + "rem", textOverflow: "clip" }}>
{/*rem unit = character px based, dynamic with font. balance contributor overflow vs longest other message*/}
{/*textoverflow "clip" forces very long @names to stretch a single line, it's silly*/}
{handles}
</Typography>
<br />
<Typography style={{ whiteSpace: "pre-wrap" }}>
<Link href={contributorsURL} target="_blank">
{contributorsMessage}
</Link>
</Typography>
<br />
<Typography fontSize={"large"}>
<Button onClick={props.onClose} size="large">
Thanks for Playing!
</Button>
</Typography>
</Modal>
);
}

@ -1,4 +1,14 @@
import { BugReport, Chat, Download, LibraryBooks, Palette, Reddit, Save, Upload } from "@mui/icons-material";
import {
BugReport,
Chat,
Download,
LibraryBooks,
Palette,
Fingerprint,
Reddit,
Save,
Upload,
} from "@mui/icons-material";
import { Box, Button, List, ListItemButton, Paper, Tooltip, Typography } from "@mui/material";
import { default as React, useRef, useState } from "react";
import { FileDiagnosticModal } from "../../Diagnostic/FileDiagnosticModal";
@ -6,6 +16,7 @@ import { ImportData, saveObject } from "../../SaveObject";
import { StyleEditorButton } from "../../Themes/ui/StyleEditorButton";
import { ThemeEditorButton } from "../../Themes/ui/ThemeEditorButton";
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
import { CreditsModal } from "./CreditsModal";
import { DeleteGameButton } from "../../ui/React/DeleteGameButton";
import { SnackbarEvents } from "../../ui/React/Snackbar";
import { ToastVariant } from "@enums";
@ -49,6 +60,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
const [importData, setImportData] = useState<ImportData | null>(null);
const [confirmResetOpen, setConfirmResetOpen] = useState(false);
const [creditsOpen, setCreditsOpen] = useState(false);
function startImport(): void {
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) return;
@ -225,7 +237,8 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
sx={{
gridArea: "links",
display: "grid",
gridTemplateAreas: `"bug bug"
gridTemplateAreas: `"credits credits"
"bug bug"
"discord reddit"
"tut tut"
"plaza plaza"`,
@ -233,6 +246,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
my: 1,
}}
>
<Tooltip title={<Typography>Start a GitHub issue to help the devs find bugs!</Typography>}>
<Button
startIcon={<BugReport />}
href="https://github.com/bitburner-official/bitburner-src/issues/new"
@ -241,6 +255,11 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
>
Report Bug
</Button>
</Tooltip>
<Button startIcon={<Fingerprint />} onClick={() => setCreditsOpen(true)} sx={{ gridArea: "credits" }}>
Credits
</Button>
<CreditsModal open={creditsOpen} onClose={() => setCreditsOpen(false)} />
<Button startIcon={<LibraryBooks />} onClick={() => setConfirmResetOpen(true)} sx={{ gridArea: "tut" }}>
Reset tutorial
</Button>