this repo has no description
1import WebpackRequire from "@moonlight-mod/types/discord/require";
2import { DownloadIconSVG, ExtensionState, TrashIconSVG } from "../types";
3import { ExtensionLoadSource } from "types/src";
4import info from "./info";
5import settings from "./settings";
6
7export enum ExtensionPage {
8 Info,
9 Description,
10 Settings
11}
12
13export default (require: typeof WebpackRequire) => {
14 const React = require("common_react");
15 const spacepack = require("spacepack_spacepack");
16 const CommonComponents = require("common_components");
17 const Flux = require("common_flux");
18
19 const { ExtensionInfo } = info(require);
20 const { Settings } = settings(require);
21 const { MoonbaseSettingsStore } = require("moonbase_stores") as ReturnType<
22 typeof import("../stores")["stores"]
23 >;
24
25 const UserProfileClasses = spacepack.findByCode(
26 "tabBarContainer",
27 "topSection"
28 )[0].exports;
29
30 const DownloadIcon = spacepack.findByCode(DownloadIconSVG)[0].exports.default;
31 const TrashIcon = spacepack.findByCode(TrashIconSVG)[0].exports.default;
32
33 function ExtensionCard({ id }: { id: string }) {
34 const [tab, setTab] = React.useState(ExtensionPage.Info);
35 const { ext, enabled, busy, update } = Flux.useStateFromStores(
36 [MoonbaseSettingsStore],
37 () => {
38 return {
39 ext: MoonbaseSettingsStore.getExtension(id),
40 enabled: MoonbaseSettingsStore.getExtensionEnabled(id),
41 busy: MoonbaseSettingsStore.busy,
42 update: MoonbaseSettingsStore.getExtensionUpdate(id)
43 };
44 }
45 );
46
47 // Why it work like that :sob:
48 if (ext == null) return <></>;
49
50 const {
51 Card,
52 CardClasses,
53 Flex,
54 Text,
55 MarkdownParser,
56 Switch,
57 TabBar,
58 Button
59 } = CommonComponents;
60
61 const tagline = ext.manifest?.meta?.tagline;
62 const settings = ext.manifest?.settings;
63 const description = ext.manifest?.meta?.description;
64
65 return (
66 <Card editable={true} className={CardClasses.card}>
67 <div className={CardClasses.cardHeader}>
68 <Flex direction={Flex.Direction.VERTICAL}>
69 <Flex direction={Flex.Direction.HORIZONTAL}>
70 <Text variant="text-md/semibold">
71 {ext.manifest?.meta?.name ?? ext.id}
72 </Text>
73 </Flex>
74
75 {tagline != null && (
76 <Text variant="text-sm/normal">
77 {MarkdownParser.parse(tagline)}
78 </Text>
79 )}
80 </Flex>
81
82 <Flex
83 direction={Flex.Direction.HORIZONTAL}
84 align={Flex.Align.END}
85 justify={Flex.Justify.END}
86 >
87 {ext.state === ExtensionState.NotDownloaded ? (
88 <Button
89 color={Button.Colors.BRAND}
90 submitting={busy}
91 onClick={() => {
92 MoonbaseSettingsStore.installExtension(id);
93 }}
94 >
95 Install
96 </Button>
97 ) : (
98 <div
99 // too lazy to learn how <Flex /> works lmao
100 style={{
101 display: "flex",
102 alignItems: "center",
103 gap: "1rem"
104 }}
105 >
106 {ext.source.type == ExtensionLoadSource.Normal && (
107 // TODO: this needs centering
108 <Button
109 color={Button.Colors.RED}
110 size={Button.Sizes.ICON}
111 submitting={busy}
112 onClick={() => {
113 MoonbaseSettingsStore.deleteExtension(id);
114 }}
115 >
116 <TrashIcon width={27} />
117 </Button>
118 )}
119
120 {update != null && (
121 <Button
122 color={Button.Colors.BRAND}
123 size={Button.Sizes.ICON}
124 submitting={busy}
125 onClick={() => {
126 MoonbaseSettingsStore.installExtension(id);
127 }}
128 >
129 <DownloadIcon width={27} />
130 </Button>
131 )}
132
133 <Switch
134 checked={enabled}
135 onChange={() => {
136 MoonbaseSettingsStore.setExtensionEnabled(id, !enabled);
137 }}
138 />
139 </div>
140 )}
141 </Flex>
142 </div>
143
144 <div className={UserProfileClasses.body}>
145 {(description != null || settings != null) && (
146 <div
147 className={UserProfileClasses.tabBarContainer}
148 style={{
149 padding: "0 10px"
150 }}
151 >
152 <TabBar
153 selectedItem={tab}
154 type="top"
155 onItemSelect={setTab}
156 className={UserProfileClasses.tabBar}
157 >
158 <TabBar.Item
159 className={UserProfileClasses.tabBarItem}
160 id={ExtensionPage.Info}
161 >
162 Info
163 </TabBar.Item>
164
165 {description != null && (
166 <TabBar.Item
167 className={UserProfileClasses.tabBarItem}
168 id={ExtensionPage.Description}
169 >
170 Description
171 </TabBar.Item>
172 )}
173
174 {settings != null && (
175 <TabBar.Item
176 className={UserProfileClasses.tabBarItem}
177 id={ExtensionPage.Settings}
178 >
179 Settings
180 </TabBar.Item>
181 )}
182 </TabBar>
183 </div>
184 )}
185
186 <Flex
187 justify={Flex.Justify.START}
188 wrap={Flex.Wrap.WRAP}
189 style={{
190 padding: "16px 16px"
191 }}
192 >
193 {tab === ExtensionPage.Info && <ExtensionInfo ext={ext} />}
194 {tab === ExtensionPage.Description && (
195 <Text variant="text-md/normal">
196 {MarkdownParser.parse(description ?? "*No description*")}
197 </Text>
198 )}
199 {tab === ExtensionPage.Settings && <Settings ext={ext} />}
200 </Flex>
201 </div>
202 </Card>
203 );
204 }
205
206 return function Moonbase() {
207 const { extensions } = Flux.useStateFromStoresObject(
208 [MoonbaseSettingsStore],
209 () => {
210 return { extensions: MoonbaseSettingsStore.extensions };
211 }
212 );
213
214 const sorted = Object.values(extensions).sort((a, b) => {
215 const aName = a.manifest.meta?.name ?? a.id;
216 const bName = b.manifest.meta?.name ?? b.id;
217 return aName.localeCompare(bName);
218 });
219
220 return (
221 <>
222 {sorted.map((ext) => (
223 <ExtensionCard id={ext.id} key={ext.id} />
224 ))}
225 </>
226 );
227 };
228};