this repo has no description

moonbase: initial crash screen with moonlight updater

Changed files
+198 -2
packages
core-extensions
src
moonbase
+32 -1
packages/core-extensions/src/moonbase/index.tsx
··· 1 - import { ExtensionWebpackModule } from "@moonlight-mod/types"; 1 + import { ExtensionWebpackModule, Patch } from "@moonlight-mod/types"; 2 + 3 + export const patches: Patch[] = [ 4 + { 5 + find: "window.DiscordErrors=", 6 + replace: [ 7 + // replace reporting line with update status 8 + { 9 + match: /,(\(0,.\.jsx\))\("p",{children:.\.[a-zA-Z]+\.Messages.ERRORS_ACTION_TO_TAKE}\)/, 10 + replacement: (_, createElement) => 11 + `,${createElement}(require("moonbase_crashScreen").UpdateText,{state:this.state,setState:this.setState.bind(this)})` 12 + }, 13 + 14 + // wrap actions field to display error details 15 + { 16 + match: /action:(.),className:/, 17 + replacement: (_, action) => `action:require("moonbase_crashScreen").wrapAction(${action},this.state),className:` 18 + }, 19 + 20 + // add update button 21 + { 22 + match: /(?<=\.ERRORS_RELOAD}\),(\(0,.\.jsx\))\(.,{}\))/, 23 + replacement: (_, createElement) => 24 + `,${createElement}(require("moonbase_crashScreen").UpdateButton,{state:this.state,setState:this.setState.bind(this)})` 25 + } 26 + ] 27 + } 28 + ]; 2 29 3 30 export const webpackModules: Record<string, ExtensionWebpackModule> = { 4 31 stores: { ··· 43 70 44 71 moonbase: { 45 72 dependencies: [{ ext: "moonbase", id: "stores" }] 73 + }, 74 + 75 + crashScreen: { 76 + dependencies: [{ id: "react" }] 46 77 } 47 78 };
+64 -1
packages/core-extensions/src/moonbase/style.css
··· 3 3 --moonbase-fg: #fffba6; 4 4 } 5 5 6 - .moonbase-settings > :first-child { 6 + .moonbase-settings> :first-child { 7 7 margin-top: 0px; 8 8 } 9 9 ··· 53 53 flex-direction: row; 54 54 gap: 8px; 55 55 } 56 + 57 + /* crash screen */ 58 + .moonbase-crash-wrapper>[class^="buttons_"] { 59 + gap: 1rem; 60 + } 61 + 62 + .moonbase-crash-wrapper { 63 + display: flex; 64 + flex-direction: column; 65 + align-items: center; 66 + gap: 1rem; 67 + max-height: 50%; 68 + } 69 + 70 + .moonbase-crash-details-wrapper { 71 + overflow-y: scroll; 72 + color: var(--text-normal); 73 + background: var(--background-secondary); 74 + border: 1px solid var(--background-tertiary); 75 + border-radius: 4px; 76 + padding: 0.5em; 77 + 78 + &::-webkit-scrollbar { 79 + width: 8px; 80 + height: 8px; 81 + } 82 + 83 + &::-webkit-scrollbar-thumb { 84 + background-clip: padding-box; 85 + border: 2px solid transparent; 86 + border-radius: 4px; 87 + background-color: var(--scrollbar-thin-thumb); 88 + min-height: 40px; 89 + } 90 + 91 + &::-webkit-scrollbar-track { 92 + border: 2px solid var(--scrollbar-thin-track); 93 + background-color: var(--scrollbar-thin-track); 94 + border-color: var(--scrollbar-thin-track); 95 + } 96 + } 97 + 98 + .moonbase-crash-details { 99 + box-sizing: border-box; 100 + padding: 0; 101 + font-family: var(--font-code); 102 + font-size: .75rem; 103 + line-height: 1rem; 104 + margin: 6px; 105 + max-width: 50vw; 106 + white-space: pre-wrap; 107 + background-clip: border-box; 108 + 109 + &>code { 110 + font-size: .875rem; 111 + line-height: 1.125rem; 112 + text-indent: 0; 113 + white-space: pre-wrap; 114 + text-size-adjust: none; 115 + display: block; 116 + user-select: text; 117 + } 118 + }
+102
packages/core-extensions/src/moonbase/webpackModules/crashScreen.tsx
··· 1 + import React from "@moonlight-mod/wp/react"; 2 + import * as Components from "@moonlight-mod/wp/discord/components/common/index"; 3 + import { useStateFromStores } from "@moonlight-mod/wp/discord/packages/flux"; 4 + import { MoonbaseSettingsStore } from "@moonlight-mod/wp/moonbase_stores"; 5 + 6 + const { Button, ButtonSizes } = Components; 7 + 8 + const logger = moonlight.getLogger("moonbase/crashScreen"); 9 + 10 + type ErrorState = { 11 + error: Error; 12 + info: { 13 + componentStack: string; 14 + }; 15 + __moonlight_update?: UpdateState; 16 + }; 17 + 18 + enum UpdateState { 19 + Ready, 20 + Working, 21 + Installed, 22 + Failed 23 + } 24 + 25 + const updateStrings: Record<UpdateState, string> = { 26 + [UpdateState.Ready]: "A new version of moonlight is available.", 27 + [UpdateState.Working]: "Updating moonlight...", 28 + [UpdateState.Installed]: "Updated moonlight. Click Reload to apply changes.", 29 + [UpdateState.Failed]: "Failed to update moonlight. Please use the installer." 30 + }; 31 + const buttonStrings: Record<UpdateState, string> = { 32 + [UpdateState.Ready]: "Update moonlight", 33 + [UpdateState.Working]: "Updating moonlight...", 34 + [UpdateState.Installed]: "", 35 + [UpdateState.Failed]: "Update failed" 36 + }; 37 + 38 + export function wrapAction(action: React.ReactNode, { error, info }: ErrorState) { 39 + return ( 40 + <div className="moonbase-crash-wrapper"> 41 + {action} 42 + <div className="moonbase-crash-details-wrapper"> 43 + <pre className="moonbase-crash-details"> 44 + <code> 45 + {error.stack} 46 + {"\n\nComponent stack:"} 47 + {info.componentStack} 48 + </code> 49 + </pre> 50 + </div> 51 + </div> 52 + ); 53 + } 54 + 55 + export function UpdateText({ state, setState }: { state: ErrorState; setState: (state: ErrorState) => void }) { 56 + if (!state.__moonlight_update) { 57 + setState({ 58 + ...state, 59 + __moonlight_update: UpdateState.Ready 60 + }); 61 + } 62 + const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion); 63 + 64 + return newVersion == null ? null : ( 65 + <p>{state.__moonlight_update !== undefined ? updateStrings[state.__moonlight_update] : ""}</p> 66 + ); 67 + } 68 + 69 + export function UpdateButton({ state, setState }: { state: ErrorState; setState: (state: ErrorState) => void }) { 70 + const newVersion = useStateFromStores([MoonbaseSettingsStore], () => MoonbaseSettingsStore.newVersion); 71 + return newVersion == null || 72 + state.__moonlight_update === UpdateState.Installed || 73 + state.__moonlight_update === undefined ? null : ( 74 + <Button 75 + size={ButtonSizes.LARGE} 76 + disabled={state.__moonlight_update !== UpdateState.Ready} 77 + onClick={() => { 78 + setState({ 79 + ...state, 80 + __moonlight_update: UpdateState.Working 81 + }); 82 + 83 + MoonbaseSettingsStore.updateMoonlight() 84 + .then(() => { 85 + setState({ 86 + ...state, 87 + __moonlight_update: UpdateState.Installed 88 + }); 89 + }) 90 + .catch((e) => { 91 + logger.error(e); 92 + setState({ 93 + ...state, 94 + __moonlight_update: UpdateState.Failed 95 + }); 96 + }); 97 + }} 98 + > 99 + {state.__moonlight_update !== undefined ? buttonStrings[state.__moonlight_update] : ""} 100 + </Button> 101 + ); 102 + }