this repo has no description
at v1.0.2 9.3 kB view raw
1import { 2 ExtensionSettingType, 3 ExtensionSettingsManifest, 4 NumberSettingType, 5 SelectSettingType 6} from "@moonlight-mod/types/config"; 7import WebpackRequire from "@moonlight-mod/types/discord/require"; 8import { MoonbaseExtension } from "../types"; 9 10type SettingsProps = { 11 ext: MoonbaseExtension; 12 name: string; 13 setting: ExtensionSettingsManifest; 14}; 15 16type SettingsComponent = React.ComponentType<SettingsProps>; 17 18export default (require: typeof WebpackRequire) => { 19 const React = require("common_react"); 20 const CommonComponents = require("common_components"); 21 const Flux = require("common_flux"); 22 23 const { MoonbaseSettingsStore } = 24 require("moonbase_stores") as typeof import("../webpackModules/stores"); 25 26 function Boolean({ ext, name, setting }: SettingsProps) { 27 const { FormSwitch } = CommonComponents; 28 const { value, displayName } = Flux.useStateFromStores( 29 [MoonbaseSettingsStore], 30 () => { 31 return { 32 value: MoonbaseSettingsStore.getExtensionConfig<boolean>( 33 ext.id, 34 name 35 ), 36 displayName: MoonbaseSettingsStore.getExtensionConfigName( 37 ext.id, 38 name 39 ) 40 }; 41 }, 42 [ext.id, name] 43 ); 44 45 return ( 46 <FormSwitch 47 value={value ?? false} 48 hideBorder={true} 49 onChange={(value: boolean) => { 50 MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value); 51 }} 52 > 53 {displayName} 54 </FormSwitch> 55 ); 56 } 57 58 function Number({ ext, name, setting }: SettingsProps) { 59 const { Slider, ControlClasses } = CommonComponents; 60 const { value, displayName } = Flux.useStateFromStores( 61 [MoonbaseSettingsStore], 62 () => { 63 return { 64 value: MoonbaseSettingsStore.getExtensionConfig<number>(ext.id, name), 65 displayName: MoonbaseSettingsStore.getExtensionConfigName( 66 ext.id, 67 name 68 ) 69 }; 70 }, 71 [ext.id, name] 72 ); 73 74 const castedSetting = setting as NumberSettingType; 75 const min = castedSetting.min ?? 0; 76 const max = castedSetting.max ?? 100; 77 78 return ( 79 <div> 80 <label className={ControlClasses.title}>{displayName}</label> 81 <Slider 82 initialValue={value ?? 0} 83 minValue={castedSetting.min ?? 0} 84 maxValue={castedSetting.max ?? 100} 85 onValueChange={(value: number) => { 86 const rounded = Math.max(min, Math.min(max, Math.round(value))); 87 MoonbaseSettingsStore.setExtensionConfig(ext.id, name, rounded); 88 }} 89 /> 90 </div> 91 ); 92 } 93 94 function String({ ext, name, setting }: SettingsProps) { 95 const { TextInput, ControlClasses } = CommonComponents; 96 const { value, displayName } = Flux.useStateFromStores( 97 [MoonbaseSettingsStore], 98 () => { 99 return { 100 value: MoonbaseSettingsStore.getExtensionConfig<string>(ext.id, name), 101 displayName: MoonbaseSettingsStore.getExtensionConfigName( 102 ext.id, 103 name 104 ) 105 }; 106 }, 107 [ext.id, name] 108 ); 109 110 return ( 111 <div> 112 <label className={ControlClasses.title}>{displayName}</label> 113 <TextInput 114 value={value ?? ""} 115 onChange={(value: string) => { 116 MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value); 117 }} 118 /> 119 </div> 120 ); 121 } 122 123 function Select({ ext, name, setting }: SettingsProps) { 124 const { ControlClasses, SingleSelect } = CommonComponents; 125 const { value, displayName } = Flux.useStateFromStores( 126 [MoonbaseSettingsStore], 127 () => { 128 return { 129 value: MoonbaseSettingsStore.getExtensionConfig<string>(ext.id, name), 130 displayName: MoonbaseSettingsStore.getExtensionConfigName( 131 ext.id, 132 name 133 ) 134 }; 135 }, 136 [ext.id, name] 137 ); 138 139 const castedSetting = setting as SelectSettingType; 140 const options = castedSetting.options; 141 142 return ( 143 <div> 144 <label className={ControlClasses.title}>{displayName}</label> 145 <SingleSelect 146 autofocus={false} 147 clearable={false} 148 value={value ?? ""} 149 options={options.map((o) => ({ value: o, label: o }))} 150 onChange={(value: string) => { 151 MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value); 152 }} 153 /> 154 </div> 155 ); 156 } 157 158 function List({ ext, name, setting }: SettingsProps) { 159 const { ControlClasses, Select, useVariableSelect, multiSelect } = 160 CommonComponents; 161 const { value, displayName } = Flux.useStateFromStores( 162 [MoonbaseSettingsStore], 163 () => { 164 return { 165 value: 166 MoonbaseSettingsStore.getExtensionConfig<string>(ext.id, name) ?? 167 [], 168 displayName: MoonbaseSettingsStore.getExtensionConfigName( 169 ext.id, 170 name 171 ) 172 }; 173 }, 174 [ext.id, name] 175 ); 176 177 const castedSetting = setting as SelectSettingType; 178 const options = castedSetting.options; 179 180 return ( 181 <div> 182 <label className={ControlClasses.title}>{displayName}</label> 183 <Select 184 autofocus={false} 185 clearable={false} 186 options={options.map((o) => ({ value: o, label: o }))} 187 {...useVariableSelect({ 188 onSelectInteraction: multiSelect, 189 value: new Set(Array.isArray(value) ? value : [value]), 190 onChange: (value: string) => { 191 MoonbaseSettingsStore.setExtensionConfig( 192 ext.id, 193 name, 194 Array.from(value) 195 ); 196 } 197 })} 198 /> 199 </div> 200 ); 201 } 202 203 function Dictionary({ ext, name, setting }: SettingsProps) { 204 const { TextInput, ControlClasses, Button, Flex } = CommonComponents; 205 const { value, displayName } = Flux.useStateFromStores( 206 [MoonbaseSettingsStore], 207 () => { 208 return { 209 value: MoonbaseSettingsStore.getExtensionConfig< 210 Record<string, string> 211 >(ext.id, name), 212 displayName: MoonbaseSettingsStore.getExtensionConfigName( 213 ext.id, 214 name 215 ) 216 }; 217 }, 218 [ext.id, name] 219 ); 220 221 const entries = Object.entries(value ?? {}); 222 223 return ( 224 <Flex direction={Flex.Direction.VERTICAL}> 225 <label className={ControlClasses.title}>{displayName}</label> 226 {entries.map(([key, val], i) => ( 227 // FIXME: stylesheets 228 <div 229 key={i} 230 style={{ 231 display: "grid", 232 height: "40px", 233 gap: "10px", 234 gridTemplateColumns: "1fr 1fr 40px" 235 }} 236 > 237 <TextInput 238 value={key} 239 onChange={(newKey: string) => { 240 entries[i][0] = newKey; 241 MoonbaseSettingsStore.setExtensionConfig( 242 ext.id, 243 name, 244 Object.fromEntries(entries) 245 ); 246 }} 247 /> 248 <TextInput 249 value={val} 250 onChange={(newValue: string) => { 251 entries[i][1] = newValue; 252 MoonbaseSettingsStore.setExtensionConfig( 253 ext.id, 254 name, 255 Object.fromEntries(entries) 256 ); 257 }} 258 /> 259 <Button 260 color={Button.Colors.RED} 261 size={Button.Sizes.ICON} 262 onClick={() => { 263 entries.splice(i, 1); 264 MoonbaseSettingsStore.setExtensionConfig( 265 ext.id, 266 name, 267 Object.fromEntries(entries) 268 ); 269 }} 270 > 271 X 272 </Button> 273 </div> 274 ))} 275 276 <Button 277 look={Button.Looks.FILLED} 278 color={Button.Colors.GREEN} 279 onClick={() => { 280 entries.push([`entry-${entries.length}`, ""]); 281 MoonbaseSettingsStore.setExtensionConfig( 282 ext.id, 283 name, 284 Object.fromEntries(entries) 285 ); 286 }} 287 > 288 Add new entry 289 </Button> 290 </Flex> 291 ); 292 } 293 294 function Setting({ ext, name, setting }: SettingsProps) { 295 const elements: Partial<Record<ExtensionSettingType, SettingsComponent>> = { 296 [ExtensionSettingType.Boolean]: Boolean, 297 [ExtensionSettingType.Number]: Number, 298 [ExtensionSettingType.String]: String, 299 [ExtensionSettingType.Select]: Select, 300 [ExtensionSettingType.List]: List, 301 [ExtensionSettingType.Dictionary]: Dictionary 302 }; 303 const element = elements[setting.type]; 304 if (element == null) return <></>; 305 return React.createElement(element, { ext, name, setting }); 306 } 307 308 function Settings({ ext }: { ext: MoonbaseExtension }) { 309 const { Flex } = CommonComponents; 310 return ( 311 <Flex direction={Flex.Direction.VERTICAL}> 312 {Object.entries(ext.manifest.settings!).map(([name, setting]) => ( 313 <Setting ext={ext} key={name} name={name} setting={setting} /> 314 ))} 315 </Flex> 316 ); 317 } 318 319 return { 320 Boolean, 321 Settings 322 }; 323};