├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ ├── feature_request.md │ └── review-extension.yaml ├── assets │ └── github_readme_title.png └── workflows │ ├── main.yml │ ├── package.yml │ ├── review-extension-issue-created.yml │ ├── signing-test.yml │ └── test.yml ├── .gitignore ├── .gitmodules ├── .npmrc ├── .storybook ├── addons.js ├── config.js ├── presets.js ├── preview-body.html ├── repair.scss ├── tsconfig.json └── webpack.config.js ├── .vscode ├── cSpell.json ├── c_cpp_properties.json ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .yarnrc ├── BuildSubprojects.js ├── BuildSubprojects.json ├── CHANGELOG.md ├── CODESTYLE.md ├── InstallAssets.js ├── InstallAssets.json ├── LICENSE.md ├── README.md ├── README_OLD.md ├── __mocks__ ├── @electron │ └── remote.js ├── diskusage.js ├── electron.js ├── ffi.js ├── leveldown.js ├── modmeta-db.js ├── original-fs.js ├── react-i18next.js ├── ref-struct.js ├── ref-union.js ├── ref.js ├── turbowalk.js ├── vortex-api.js ├── wholocks.js └── winapi-bindings.js ├── __tests__ ├── MainWindow.test.jsx ├── NXMUrl.test.js ├── actions.category_management.test.js ├── actions.download_management.test.js ├── actions.feedback.test.js ├── actions.gamemode_management.test.js ├── actions.installer_fomod.test.js ├── actions.mod_management.test.js ├── actions.nexus_integration.test.js ├── actions.profile_management.test.js ├── actions.savegame_management.test.js ├── actions.session.test.js ├── actions.settings_interface.test.js ├── actions.settings_metaserver.test.js ├── actions.starter_dashlet.test.js ├── actions.test.js ├── actions.updater.test.js ├── elevated.test.js ├── fblo.updateset.test.js ├── fs.test.js ├── gamemode_management.selectors.test.js ├── getAttr.test.js ├── modGrouping.test.js ├── network.test.js ├── reducer.session.test.js ├── reducers.category_management.test.js ├── reducers.download_management.test.js ├── reducers.feedback.test.js ├── reducers.firststeps_dashlet.test.js ├── reducers.gamemode_management.test.js ├── reducers.installer_fomod.test.js ├── reducers.mod_management.test.js ├── reducers.nexus_integration.test.js ├── reducers.notifications.test.js ├── reducers.profile_management.test.js ├── reducers.savegame_management.test.js ├── reducers.settings_interface.test.js ├── reducers.settings_metaserver.test.js ├── reducers.starter_dashlet.test.js ├── reducers.tables.test.js ├── reducers.updater.test.js ├── reducers.window.test.js ├── relativeTime.test.js ├── storeHelper.test.js ├── util.deepMerge.test.js ├── util.test.js ├── util.transferpath.test.js └── utils.nmm_import_tool.test.js ├── app ├── .gitignore ├── .yarnclean ├── package.json └── yarn.lock ├── appveyor.yml ├── assets ├── dotnetprobe.exe ├── fonts │ ├── Inter-Black.ttf │ ├── Inter-BlackItalic.ttf │ ├── Inter-Bold.ttf │ ├── Inter-BoldItalic.ttf │ ├── Inter-ExtraBold.ttf │ ├── Inter-ExtraBoldItalic.ttf │ ├── Inter-ExtraLight.ttf │ ├── Inter-ExtraLightItalic.ttf │ ├── Inter-Italic.ttf │ ├── Inter-Light.ttf │ ├── Inter-LightItalic.ttf │ ├── Inter-Medium.ttf │ ├── Inter-MediumItalic.ttf │ ├── Inter-Regular.ttf │ ├── Inter-SemiBold.ttf │ ├── Inter-SemiBoldItalic.ttf │ ├── Inter-Thin.ttf │ ├── Inter-ThinItalic.ttf │ ├── Montserrat-Black.ttf │ ├── Montserrat-BlackItalic.ttf │ ├── Montserrat-Bold.ttf │ ├── Montserrat-BoldItalic.ttf │ ├── Montserrat-ExtraBold.ttf │ ├── Montserrat-ExtraBoldItalic.ttf │ ├── Montserrat-ExtraLight.ttf │ ├── Montserrat-ExtraLightItalic.ttf │ ├── Montserrat-Italic.ttf │ ├── Montserrat-Light.ttf │ ├── Montserrat-LightItalic.ttf │ ├── Montserrat-Medium.ttf │ ├── Montserrat-MediumItalic.ttf │ ├── Montserrat-Regular.ttf │ ├── Montserrat-SemiBold.ttf │ ├── Montserrat-SemiBoldItalic.ttf │ ├── Montserrat-Thin.ttf │ ├── Montserrat-ThinItalic.ttf │ ├── Roboto-Black.ttf │ ├── Roboto-BlackItalic.ttf │ ├── Roboto-Bold.ttf │ ├── Roboto-BoldItalic.ttf │ ├── Roboto-Italic.ttf │ ├── Roboto-Light.ttf │ ├── Roboto-LightItalic.ttf │ ├── Roboto-Medium.ttf │ ├── Roboto-MediumItalic.ttf │ ├── Roboto-Regular.ttf │ ├── Roboto-Thin.ttf │ ├── Roboto-ThinItalic.ttf │ └── icons.svg ├── images │ ├── Thumbs.db │ ├── ad-banner-large.png │ ├── ad-banner.png │ ├── bg.png │ ├── dashlets │ │ ├── add-game.png │ │ ├── add-mods.png │ │ ├── install-tools.png │ │ └── login-link.png │ ├── license_nucleo.txt │ ├── log-in-bg.png │ ├── nexus.svg │ ├── noavatar.png │ ├── splash.png │ ├── splash_old.png │ ├── vortex.ico │ └── vortex.png ├── licenses │ ├── Apache-2.0.md │ ├── BSD-2-Clause.md │ ├── BSD-3-Clause.md │ ├── GPL-2.0.md │ ├── GPL-3.0.md │ ├── ISC.md │ ├── LGPL-3.0.md │ └── MIT.md └── vcruntime │ ├── api-ms-win-core-console-l1-1-0.dll │ ├── api-ms-win-core-datetime-l1-1-0.dll │ ├── api-ms-win-core-debug-l1-1-0.dll │ ├── api-ms-win-core-errorhandling-l1-1-0.dll │ ├── api-ms-win-core-file-l1-1-0.dll │ ├── api-ms-win-core-file-l1-2-0.dll │ ├── api-ms-win-core-file-l2-1-0.dll │ ├── api-ms-win-core-handle-l1-1-0.dll │ ├── api-ms-win-core-heap-l1-1-0.dll │ ├── api-ms-win-core-interlocked-l1-1-0.dll │ ├── api-ms-win-core-libraryloader-l1-1-0.dll │ ├── api-ms-win-core-localization-l1-2-0.dll │ ├── api-ms-win-core-memory-l1-1-0.dll │ ├── api-ms-win-core-namedpipe-l1-1-0.dll │ ├── api-ms-win-core-processenvironment-l1-1-0.dll │ ├── api-ms-win-core-processthreads-l1-1-0.dll │ ├── api-ms-win-core-processthreads-l1-1-1.dll │ ├── api-ms-win-core-profile-l1-1-0.dll │ ├── api-ms-win-core-rtlsupport-l1-1-0.dll │ ├── api-ms-win-core-string-l1-1-0.dll │ ├── api-ms-win-core-synch-l1-1-0.dll │ ├── api-ms-win-core-synch-l1-2-0.dll │ ├── api-ms-win-core-sysinfo-l1-1-0.dll │ ├── api-ms-win-core-timezone-l1-1-0.dll │ ├── api-ms-win-core-util-l1-1-0.dll │ ├── api-ms-win-crt-conio-l1-1-0.dll │ ├── api-ms-win-crt-convert-l1-1-0.dll │ ├── api-ms-win-crt-environment-l1-1-0.dll │ ├── api-ms-win-crt-filesystem-l1-1-0.dll │ ├── api-ms-win-crt-heap-l1-1-0.dll │ ├── api-ms-win-crt-locale-l1-1-0.dll │ ├── api-ms-win-crt-math-l1-1-0.dll │ ├── api-ms-win-crt-multibyte-l1-1-0.dll │ ├── api-ms-win-crt-private-l1-1-0.dll │ ├── api-ms-win-crt-process-l1-1-0.dll │ ├── api-ms-win-crt-runtime-l1-1-0.dll │ ├── api-ms-win-crt-stdio-l1-1-0.dll │ ├── api-ms-win-crt-string-l1-1-0.dll │ ├── api-ms-win-crt-time-l1-1-0.dll │ ├── api-ms-win-crt-utility-l1-1-0.dll │ ├── concrt140.dll │ ├── msvcp140.dll │ ├── msvcp140_1.dll │ ├── msvcp140_2.dll │ ├── msvcp140_atomic_wait.dll │ ├── msvcp140_codecvt_ids.dll │ ├── ucrtbase.dll │ ├── vcamp140.dll │ ├── vccorlib140.dll │ ├── vcomp140.dll │ ├── vcruntime140.dll │ └── vcruntime140_1.dll ├── bootstrap.ps1 ├── build ├── amd64-unicode │ └── AccessControl.dll ├── icon.ico ├── installer.nsh ├── installerSidebar.bmp ├── installer_ci.nsh ├── x86-ansi │ └── AccessControl.dll └── x86-unicode │ └── AccessControl.dll ├── checkPackages.js ├── copy_sourcemaps.js ├── createMD5List.js ├── dev-app-update.yml ├── download-buildpatchtool.ps1 ├── download-codesigntool.ps1 ├── electron-builder-advanced.json ├── electron-builder-ci.json ├── electron-builder-config-old.json ├── electron-builder-config.json ├── electron-builder-oneclick.json ├── electron-builder-test.json ├── electron-builder-web.json ├── icons └── custom │ ├── 753.svg │ ├── nexus-header.svg │ ├── nexus.svg │ └── spinner_new.svg ├── jsconfig.json ├── licenseFormat.json ├── locales └── en │ └── common.json ├── package.json ├── postinstall.js ├── samples └── sample-extension │ ├── package.json │ ├── src │ └── index.ts │ ├── tsconfig.json │ ├── webpack.config.js │ └── yarn.lock ├── setupTests.js ├── sign.js ├── src ├── actions │ ├── app.ts │ ├── index.ts │ ├── loadOrder.ts │ ├── notificationSettings.ts │ ├── notifications.ts │ ├── safeCreateAction.ts │ ├── session.ts │ ├── tables.ts │ ├── user.ts │ └── window.ts ├── app │ ├── Application.ts │ ├── MainWindow.ts │ ├── SplashScreen.ts │ └── TrayIcon.ts ├── constants.ts ├── controls │ ├── ActionContextMenu.tsx │ ├── ActionControl.tsx │ ├── ActionDropdown.tsx │ ├── Advanced.tsx │ ├── Banner.tsx │ ├── Collapse.tsx │ ├── CollapseIcon.tsx │ ├── ContextMenu.tsx │ ├── CopyClipboardInput.tsx │ ├── Dashlet.tsx │ ├── DraggableList.tsx │ ├── DraggableListItem.tsx │ ├── Dropdown.tsx │ ├── DropdownButton.tsx │ ├── Dropzone.tsx │ ├── DynDiv.tsx │ ├── DynamicProps.tsx │ ├── EmptyPlaceholder.tsx │ ├── ErrorBoundary.tsx │ ├── ExtensibleControl.tsx │ ├── ExtensionGate.tsx │ ├── FlexLayout.tsx │ ├── FormFeedback.tsx │ ├── FormFields.tsx │ ├── FormInput.tsx │ ├── Icon.base.tsx │ ├── Icon.stories.js │ ├── Icon.tsx │ ├── IconBar.tsx │ ├── IconBar.unfinished_stories.js │ ├── Image.tsx │ ├── InputButton.tsx │ ├── Modal.tsx │ ├── More.tsx │ ├── Overlay.tsx │ ├── OverlayTrigger.tsx │ ├── PlaceholderTextArea.tsx │ ├── PortalMenu.tsx │ ├── ProgressBar.tsx │ ├── RadialProgress.tsx │ ├── ReactSelectWrap.tsx │ ├── SelectUpDown.tsx │ ├── Spinner.tsx │ ├── Step.tsx │ ├── Steps.tsx │ ├── Table.tsx │ ├── Timer.tsx │ ├── Toggle.tsx │ ├── ToolIcon.tsx │ ├── ToolbarDropdown.tsx │ ├── ToolbarIcon.tsx │ ├── TooltipControls.tsx │ ├── TriStateCheckbox.tsx │ ├── Usage.tsx │ ├── VisibilityProxy.tsx │ ├── Webview.tsx │ ├── ZoomableImage.tsx │ ├── api.ts │ ├── constants.ts │ └── table │ │ ├── DateTimeFilter.tsx │ │ ├── GameFilter.tsx │ │ ├── GroupingRow.tsx │ │ ├── HeaderCell.tsx │ │ ├── MyTable.tsx │ │ ├── NumericFilter.tsx │ │ ├── OptionsFilter.tsx │ │ ├── SortIndicator.tsx │ │ ├── TableDetail.tsx │ │ ├── TableRow.tsx │ │ └── TextFilter.tsx ├── extensions │ ├── about_dialog │ │ ├── index.ts │ │ ├── types │ │ │ └── ILicense.ts │ │ └── views │ │ │ └── AboutPage.tsx │ ├── analytics │ │ ├── actions │ │ │ └── analytics.action.ts │ │ ├── analytics │ │ │ ├── AnalyticsGA4.ts │ │ │ ├── AnalyticsUA.ts │ │ │ ├── events.ts │ │ │ └── navigation.ts │ │ ├── constants.ts │ │ ├── ga4mp │ │ │ ├── README.md │ │ │ └── ga4mp.esm.js │ │ ├── index.ts │ │ ├── reducers │ │ │ └── settings.reducer.ts │ │ ├── types.ts │ │ └── views │ │ │ └── SettingsAnalytics.tsx │ ├── announcement_dashlet │ │ ├── AnnouncementDashlet.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── announcements.ts │ │ │ ├── persistent.ts │ │ │ └── surveys.ts │ │ ├── types.ts │ │ └── util.ts │ ├── browser │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers.ts │ │ ├── types.ts │ │ └── views │ │ │ └── BrowserView.tsx │ ├── category_management │ │ ├── actions │ │ │ ├── category.ts │ │ │ └── session.ts │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── category.ts │ │ │ └── session.ts │ │ ├── selectors.ts │ │ ├── types │ │ │ ├── ICategoryDictionary.ts │ │ │ └── ITrees.ts │ │ ├── util │ │ │ ├── CategoryFilter.tsx │ │ │ ├── createTreeDataObject.ts │ │ │ ├── generateSubtitle.ts │ │ │ └── retrieveCategoryPath.ts │ │ └── views │ │ │ ├── CategoryDialog.tsx │ │ │ └── CategoryList.tsx │ ├── dashboard │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducer.ts │ │ ├── types │ │ │ └── IDashletProps.ts │ │ └── views │ │ │ ├── Dashboard.tsx │ │ │ ├── FixedItem.tsx │ │ │ ├── PackeryGrid.tsx │ │ │ ├── PackeryItem.tsx │ │ │ └── Settings.tsx │ ├── diagnostics_files │ │ ├── index.ts │ │ ├── types │ │ │ └── ISession.ts │ │ ├── util │ │ │ └── loadVortexLogs.ts │ │ └── views │ │ │ └── DiagnosticsFilesDialog.tsx │ ├── download_management │ │ ├── DownloadManager.ts │ │ ├── DownloadObserver.ts │ │ ├── FileAssembler.ts │ │ ├── SpeedCalculator.ts │ │ ├── actions │ │ │ ├── settings.ts │ │ │ ├── state.ts │ │ │ └── transactions.ts │ │ ├── downloadAttributes.tsx │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── settings.ts │ │ │ ├── state.ts │ │ │ └── transactions.ts │ │ ├── selectors.ts │ │ ├── texts.ts │ │ ├── types │ │ │ ├── IChunk.ts │ │ │ ├── IDownload.ts │ │ │ ├── IDownloadJob.ts │ │ │ ├── IDownloadResult.ts │ │ │ ├── ProgressCallback.ts │ │ │ └── ProtocolHandlers.ts │ │ ├── util │ │ │ ├── downloadDirectory.ts │ │ │ ├── getDownloadGames.ts │ │ │ ├── getDownloadPath.ts │ │ │ ├── postprocessDownload.ts │ │ │ ├── queryDLInfo.ts │ │ │ ├── setDownloadGames.ts │ │ │ └── throttle.ts │ │ └── views │ │ │ ├── Dashlet.tsx │ │ │ ├── DownloadGameList.tsx │ │ │ ├── DownloadGraph.tsx │ │ │ ├── DownloadProgressFilter.tsx │ │ │ ├── DownloadView.tsx │ │ │ ├── FileTime.tsx │ │ │ ├── Settings.tsx │ │ │ ├── ShutdownButton.tsx │ │ │ └── SpeedOMeter.tsx │ ├── extension_manager │ │ ├── BrowseExtensions.tsx │ │ ├── ExtensionManager.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── installExtension.ts │ │ ├── reducers.ts │ │ ├── tableAttributes.tsx │ │ ├── types.ts │ │ └── util.ts │ ├── file_based_loadorder │ │ ├── UpdateSet.ts │ │ ├── actions │ │ │ ├── loadOrder.ts │ │ │ └── session.ts │ │ ├── collections │ │ │ └── loadOrder.ts │ │ ├── gameSupport.ts │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── loadOrder.ts │ │ │ └── session.ts │ │ ├── types │ │ │ ├── collections.ts │ │ │ └── types.ts │ │ ├── util.ts │ │ └── views │ │ │ ├── FileBasedLoadOrderPage.tsx │ │ │ ├── FilterBox.tsx │ │ │ ├── InfoPanel.tsx │ │ │ ├── ItemRenderer.tsx │ │ │ ├── LoadOrderCollections.tsx │ │ │ └── loadOrderIndex.tsx │ ├── file_preview │ │ └── index.ts │ ├── firststeps_dashlet │ │ ├── Dashlet.tsx │ │ ├── IToDo.ts │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers.ts │ │ └── todos.tsx │ ├── gamemode_management │ │ ├── GameModeManager.ts │ │ ├── actions │ │ │ ├── discovery.ts │ │ │ ├── persistent.ts │ │ │ ├── session.ts │ │ │ └── settings.ts │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── discovery.ts │ │ │ ├── persistent.ts │ │ │ ├── session.ts │ │ │ └── settings.ts │ │ ├── selectors.ts │ │ ├── types │ │ │ ├── IDiscoveryResult.ts │ │ │ ├── IGameStored.ts │ │ │ ├── IModType.ts │ │ │ └── IToolStored.ts │ │ ├── util │ │ │ ├── ProcessMonitor.ts │ │ │ ├── Progress.ts │ │ │ ├── discovery.ts │ │ │ ├── getDriveList.ts │ │ │ ├── getGame.ts │ │ │ ├── modTypeExtensions.ts │ │ │ └── queryGameInfo.ts │ │ └── views │ │ │ ├── GameInfoPopover.tsx │ │ │ ├── GamePicker.tsx │ │ │ ├── GameRow.tsx │ │ │ ├── GameThumbnail.tsx │ │ │ ├── HideGameIcon.tsx │ │ │ ├── ModTypeWidget.tsx │ │ │ ├── NoGameDashlet.tsx │ │ │ ├── PathSelection.tsx │ │ │ ├── ProgressFooter.tsx │ │ │ ├── RecentlyManagedDashlet.tsx │ │ │ └── ShowHiddenButton.tsx │ ├── gameversion_management │ │ ├── GameVersionManager.ts │ │ ├── index.ts │ │ ├── types │ │ │ └── IGameVersionProvider.ts │ │ └── util │ │ │ ├── getGameVersion.ts │ │ │ └── validation.ts │ ├── hardlink_activator │ │ └── index.ts │ ├── history_management │ │ ├── HistoryDialog.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers.ts │ │ └── types.ts │ ├── index.ts │ ├── ini_prep │ │ ├── TweakList.tsx │ │ ├── gameSupport.ts │ │ └── index.ts │ ├── installer_fomod │ │ ├── actions │ │ │ ├── installerUI.ts │ │ │ └── settings.ts │ │ ├── constants.ts │ │ ├── delegates │ │ │ ├── Context.ts │ │ │ ├── Core.ts │ │ │ ├── DelegateBase.ts │ │ │ ├── Ini.ts │ │ │ ├── Plugins.ts │ │ │ └── UI.ts │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── installerUI.ts │ │ │ └── settings.ts │ │ ├── types │ │ │ └── interface.ts │ │ ├── util │ │ │ ├── gameSupport.ts │ │ │ └── netVersion.ts │ │ └── views │ │ │ ├── InstallerDialog.tsx │ │ │ └── Workarounds.tsx │ ├── installer_nested_fomod │ │ └── index.ts │ ├── instructions_overlay │ │ ├── Container.tsx │ │ ├── InstructionsOverlay.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ └── reducer.ts │ ├── mod_load_order │ │ ├── actions │ │ │ ├── loadOrder.ts │ │ │ └── settings.ts │ │ ├── collections │ │ │ └── loadOrder.ts │ │ ├── gameSupport.ts │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── loadOrder.ts │ │ │ └── settings.ts │ │ ├── types │ │ │ ├── collections.ts │ │ │ └── types.ts │ │ ├── util.ts │ │ └── views │ │ │ ├── DefaultInfoPanel.tsx │ │ │ ├── DefaultItemRenderer.tsx │ │ │ ├── DraggableList.tsx │ │ │ ├── LoadOrderCollections.tsx │ │ │ └── LoadOrderPage.tsx │ ├── mod_management │ │ ├── InstallContext.ts │ │ ├── InstallManager.ts │ │ ├── LinkingDeployment.ts │ │ ├── actions │ │ │ ├── deployment.ts │ │ │ ├── mods.ts │ │ │ ├── session.ts │ │ │ ├── settings.ts │ │ │ └── transactions.ts │ │ ├── constants.ts │ │ ├── eventHandlers.ts │ │ ├── index.ts │ │ ├── listInstaller.tsx │ │ ├── modActivation.ts │ │ ├── modAttributes.tsx │ │ ├── modIdManager.ts │ │ ├── modMerging.ts │ │ ├── preStartDeployHook.ts │ │ ├── reducers │ │ │ ├── deployment.ts │ │ │ ├── mods.ts │ │ │ ├── session.ts │ │ │ ├── settings.ts │ │ │ └── transactions.ts │ │ ├── selectors.ts │ │ ├── stagingDirectory.ts │ │ ├── texts.ts │ │ ├── types │ │ │ ├── IDependency.ts │ │ │ ├── IDeployOptions.ts │ │ │ ├── IDeploymentManifest.ts │ │ │ ├── IDeploymentMethod.ts │ │ │ ├── IFileEntry.ts │ │ │ ├── IFileMerge.ts │ │ │ ├── IInstallContext.ts │ │ │ ├── IInstallOptions.ts │ │ │ ├── IInstallResult.ts │ │ │ ├── IMod.ts │ │ │ ├── IModInstaller.ts │ │ │ ├── IModProps.ts │ │ │ ├── IModSource.ts │ │ │ ├── IRemoveModOptions.ts │ │ │ ├── IResolvedMerger.ts │ │ │ ├── IStateMods.ts │ │ │ ├── InstallFunc.ts │ │ │ └── TestSupported.ts │ │ ├── util │ │ │ ├── BlacklistSet.ts │ │ │ ├── ModHistory.ts │ │ │ ├── VersionFilter.tsx │ │ │ ├── activationStore.ts │ │ │ ├── allTypesSupported.ts │ │ │ ├── basicInstaller.ts │ │ │ ├── combine.ts │ │ │ ├── dependencies.ts │ │ │ ├── deploy.ts │ │ │ ├── deploymentMethods.ts │ │ │ ├── exceptions.ts │ │ │ ├── externalChanges.ts │ │ │ ├── filterModInfo.ts │ │ │ ├── getInstallPath.ts │ │ │ ├── manifest_formats │ │ │ │ └── format_1.ts │ │ │ ├── metaLookupMatch.ts │ │ │ ├── modGrouping.ts │ │ │ ├── modName.ts │ │ │ ├── modReference.ts │ │ │ ├── modSource.ts │ │ │ ├── modUpdateState.ts │ │ │ ├── queryGameId.ts │ │ │ ├── refreshMods.ts │ │ │ ├── removeMods.ts │ │ │ ├── resolvePath.ts │ │ │ ├── sort.ts │ │ │ ├── testModReference.ts │ │ │ └── versionClean.ts │ │ └── views │ │ │ ├── ActivationButton.tsx │ │ │ ├── Author.tsx │ │ │ ├── CheckModVersionsButton.tsx │ │ │ ├── DeactivationButton.tsx │ │ │ ├── Description.tsx │ │ │ ├── DuplicatesDialog.tsx │ │ │ ├── ExternalChangeDialog.tsx │ │ │ ├── FixDeploymentDialog.tsx │ │ │ ├── InstallArchiveButton.tsx │ │ │ ├── ModList.tsx │ │ │ ├── Settings.tsx │ │ │ ├── URLInput.tsx │ │ │ ├── VersionChangelogButton.tsx │ │ │ ├── VersionIconButton.tsx │ │ │ └── Workarounds.tsx │ ├── mod_spotlights_dashlet │ │ ├── ModSpotlightsDashlet.tsx │ │ ├── index.ts │ │ └── types.ts │ ├── move_activator │ │ └── index.ts │ ├── news_dashlet │ │ ├── APIDashlet.tsx │ │ ├── BaseDashlet.tsx │ │ ├── RSSDashlet.tsx │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── rss.ts │ │ └── types.ts │ ├── nexus_integration │ │ ├── NXMUrl.ts │ │ ├── actions │ │ │ ├── account.ts │ │ │ ├── persistent.ts │ │ │ ├── session.ts │ │ │ └── settings.ts │ │ ├── attributes.tsx │ │ ├── constants.ts │ │ ├── eventHandlers.ts │ │ ├── index.tsx │ │ ├── reducers │ │ │ ├── account.ts │ │ │ ├── persistent.ts │ │ │ ├── session.ts │ │ │ └── settings.ts │ │ ├── selectors.ts │ │ ├── texts.ts │ │ ├── types │ │ │ ├── IJWTAccessToken.ts │ │ │ ├── INexusAPIExtension.ts │ │ │ └── IValidateKeyData.ts │ │ ├── util.ts │ │ ├── util │ │ │ ├── UIDs.ts │ │ │ ├── checkModsVersion.ts │ │ │ ├── chromeAllowScheme.ts │ │ │ ├── chromePath.ts │ │ │ ├── convertGameId.ts │ │ │ ├── endorseMod.ts │ │ │ ├── graphQueries.ts │ │ │ ├── guessModID.ts │ │ │ ├── nexusmodslogo.js │ │ │ ├── oauth.ts │ │ │ ├── oauth_success.html │ │ │ ├── retrieveCategories.ts │ │ │ ├── sso.ts │ │ │ ├── submitFeedback.ts │ │ │ ├── tracking.tsx │ │ │ ├── transformUserInfo.ts │ │ │ └── vortexicon.js │ │ └── views │ │ │ ├── DashboardBanner.tsx │ │ │ ├── EndorseModButton.tsx │ │ │ ├── EndorsementFilter.tsx │ │ │ ├── FreeUserDLDialog.tsx │ │ │ ├── GoPremiumDashlet.tsx │ │ │ ├── LoginDialog.tsx │ │ │ ├── LoginIcon.tsx │ │ │ ├── NexusModIdDetail.tsx │ │ │ ├── PremiumNagBanner.tsx │ │ │ └── Settings.tsx │ ├── null_activator │ │ └── index.ts │ ├── onboarding_dashlet │ │ ├── Dashlet.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers.ts │ │ ├── steps.ts │ │ └── views │ │ │ └── Overlay.tsx │ ├── profile_management │ │ ├── actions │ │ │ ├── profiles.ts │ │ │ ├── settings.ts │ │ │ └── transferSetup.ts │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── reducers │ │ │ ├── profiles.ts │ │ │ ├── settings.ts │ │ │ └── transferSetup.ts │ │ ├── selectors.ts │ │ ├── sync.ts │ │ ├── texts.ts │ │ ├── types │ │ │ ├── Errors.ts │ │ │ ├── IProfile.ts │ │ │ └── IProfileFeature.ts │ │ ├── util │ │ │ └── manage.ts │ │ └── views │ │ │ ├── Connector.tsx │ │ │ ├── Line.tsx │ │ │ ├── ProfileEdit.tsx │ │ │ ├── ProfileItem.tsx │ │ │ ├── ProfileView.tsx │ │ │ ├── TransferDialog.tsx │ │ │ └── TransferIcon.tsx │ ├── recovery │ │ ├── Workarounds.tsx │ │ └── index.ts │ ├── settings_application │ │ ├── SettingsVortex.tsx │ │ ├── index.ts │ │ └── texts.ts │ ├── settings_interface │ │ ├── SettingsInterface.tsx │ │ ├── actions │ │ │ ├── automation.ts │ │ │ └── interface.ts │ │ ├── index.ts │ │ ├── languagemap.ts │ │ ├── reducers │ │ │ ├── automation.ts │ │ │ └── interface.ts │ │ └── texts.ts │ ├── settings_metaserver │ │ ├── SettingsMetaserver.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers.ts │ │ └── texts.ts │ ├── starter_dashlet │ │ ├── AddToolButton.tsx │ │ ├── BoxWithHandle.tsx │ │ ├── EnvButton.tsx │ │ ├── Environment.tsx │ │ ├── Tool.tsx │ │ ├── ToolButton.tsx │ │ ├── ToolEditDialog.tsx │ │ ├── Tools.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers.ts │ │ ├── types.ts │ │ ├── useDebouncedCallback.ts │ │ └── util.ts │ ├── sticky_mods │ │ └── index.ts │ ├── symlink_activator │ │ └── index.ts │ ├── symlink_activator_elevate │ │ ├── Settings.tsx │ │ ├── actions.ts │ │ ├── index.ts │ │ ├── reducers.ts │ │ ├── remoteCode.ts │ │ └── walk.ts │ ├── test_runner │ │ └── index.ts │ ├── tool_variables_base │ │ └── index.ts │ └── updater │ │ ├── SettingsUpdate.tsx │ │ ├── actions.ts │ │ ├── autoupdater.ts │ │ ├── index.ts │ │ └── reducers.ts ├── index.dev.html ├── index.html ├── index.ts ├── main.ts ├── reducers │ ├── app.ts │ ├── index.ts │ ├── loadOrder.ts │ ├── notificationSettings.ts │ ├── notifications.ts │ ├── session.ts │ ├── tables.ts │ ├── user.ts │ └── window.ts ├── renderer.tsx ├── splash.html ├── splash.ts ├── stylesheets │ ├── bootstrap-override.scss │ ├── bootstrap │ │ ├── _bootstrap-compass.scss │ │ ├── _bootstrap-mincer.scss │ │ ├── _bootstrap-sprockets.scss │ │ ├── _bootstrap.scss │ │ ├── bootstrap │ │ │ ├── _alerts.scss │ │ │ ├── _badges.scss │ │ │ ├── _breadcrumbs.scss │ │ │ ├── _button-groups.scss │ │ │ ├── _buttons.scss │ │ │ ├── _carousel.scss │ │ │ ├── _close.scss │ │ │ ├── _code.scss │ │ │ ├── _component-animations.scss │ │ │ ├── _dropdowns.scss │ │ │ ├── _forms.scss │ │ │ ├── _glyphicons.scss │ │ │ ├── _grid.scss │ │ │ ├── _input-groups.scss │ │ │ ├── _jumbotron.scss │ │ │ ├── _labels.scss │ │ │ ├── _list-group.scss │ │ │ ├── _media.scss │ │ │ ├── _mixins.scss │ │ │ ├── _modals.scss │ │ │ ├── _navbar.scss │ │ │ ├── _navs.scss │ │ │ ├── _normalize.scss │ │ │ ├── _pager.scss │ │ │ ├── _pagination.scss │ │ │ ├── _panels.scss │ │ │ ├── _popovers.scss │ │ │ ├── _print.scss │ │ │ ├── _progress-bars.scss │ │ │ ├── _responsive-embed.scss │ │ │ ├── _responsive-utilities.scss │ │ │ ├── _scaffolding.scss │ │ │ ├── _tables.scss │ │ │ ├── _theme.scss │ │ │ ├── _thumbnails.scss │ │ │ ├── _tooltip.scss │ │ │ ├── _type.scss │ │ │ ├── _utilities.scss │ │ │ ├── _variables.scss │ │ │ ├── _wells.scss │ │ │ └── mixins │ │ │ │ ├── _alerts.scss │ │ │ │ ├── _background-variant.scss │ │ │ │ ├── _border-radius.scss │ │ │ │ ├── _buttons.scss │ │ │ │ ├── _center-block.scss │ │ │ │ ├── _clearfix.scss │ │ │ │ ├── _forms.scss │ │ │ │ ├── _gradients.scss │ │ │ │ ├── _grid-framework.scss │ │ │ │ ├── _grid.scss │ │ │ │ ├── _hide-text.scss │ │ │ │ ├── _image.scss │ │ │ │ ├── _labels.scss │ │ │ │ ├── _list-group.scss │ │ │ │ ├── _nav-divider.scss │ │ │ │ ├── _nav-vertical-align.scss │ │ │ │ ├── _opacity.scss │ │ │ │ ├── _pagination.scss │ │ │ │ ├── _panels.scss │ │ │ │ ├── _progress-bar.scss │ │ │ │ ├── _reset-filter.scss │ │ │ │ ├── _reset-text.scss │ │ │ │ ├── _resize.scss │ │ │ │ ├── _responsive-visibility.scss │ │ │ │ ├── _size.scss │ │ │ │ ├── _tab-focus.scss │ │ │ │ ├── _table-row.scss │ │ │ │ ├── _text-emphasis.scss │ │ │ │ ├── _text-overflow.scss │ │ │ │ └── _vendor-prefixes.scss │ │ └── readme.txt │ ├── datepicker │ │ ├── datepicker.scss │ │ ├── mixins.scss │ │ └── variables.scss │ ├── desktop.scss │ ├── details.scss │ ├── functions.scss │ ├── loadingScreen.scss │ ├── react-select-variables.scss │ ├── react-select.scss │ ├── react-sortable-tree-original.scss │ ├── react-sortable-tree.scss │ ├── resizer.scss │ ├── style.scss │ ├── thirdparty.scss │ ├── variables.scss │ └── vortex │ │ ├── banner.scss │ │ ├── bbcode.scss │ │ ├── bebasneue.scss │ │ ├── browser.scss │ │ ├── charts.scss │ │ ├── collapse.scss │ │ ├── collapseicon.scss │ │ ├── dashlet-rss.scss │ │ ├── dashlet.scss │ │ ├── dialog-about.scss │ │ ├── dialog-categories.scss │ │ ├── dialog-diagnostic-files.scss │ │ ├── dialog-extensions.scss │ │ ├── dialog-external-change.scss │ │ ├── dialog-fix-deployment.scss │ │ ├── dialog-fomod.scss │ │ ├── dialog-history.scss │ │ ├── dialog-login.scss │ │ ├── dialog-search-paths.scss │ │ ├── dialogs.scss │ │ ├── dropzone.scss │ │ ├── gamepicker.scss │ │ ├── globals.scss │ │ ├── hover-menu.scss │ │ ├── icon.scss │ │ ├── iconbar.scss │ │ ├── instructions-overlay.scss │ │ ├── inter.scss │ │ ├── layout.scss │ │ ├── main-window.scss │ │ ├── montserrat.scss │ │ ├── more.scss │ │ ├── navbar.scss │ │ ├── nexusmods.scss │ │ ├── notification.scss │ │ ├── page-dashboard.scss │ │ ├── page-download.scss │ │ ├── page-extensions.scss │ │ ├── page-game.scss │ │ ├── page-mod-load-order.scss │ │ ├── page-mod.scss │ │ ├── page-profile.scss │ │ ├── page-settings.scss │ │ ├── placeholder.scss │ │ ├── portal-menu.scss │ │ ├── progress.scss │ │ ├── progressbar.scss │ │ ├── quicklaunch.scss │ │ ├── radial.scss │ │ ├── roboto.scss │ │ ├── starter.scss │ │ ├── steps.scss │ │ ├── supertable.scss │ │ ├── table.scss │ │ ├── timer.scss │ │ ├── todo.scss │ │ ├── toggle.scss │ │ ├── tristatecheckbox.scss │ │ ├── usage.scss │ │ └── window-controls.scss ├── toJSONSchema.ts ├── types │ ├── Extension.ts │ ├── IActionDefinition.ts │ ├── IAttributeState.ts │ ├── IBannerOptions.ts │ ├── IComponentContext.ts │ ├── IDialog.ts │ ├── IDiscoveredTool.ts │ ├── IDynDivOptions.ts │ ├── IError.ts │ ├── IExecInfo.ts │ ├── IExtensionContext.ts │ ├── IExtensionProvider.ts │ ├── IGame.ts │ ├── IGame.validator.json │ ├── IGame.validator.ts │ ├── IGameStore.ts │ ├── IGameStoreEntry.ts │ ├── II18NProps.ts │ ├── IMainPage.ts │ ├── IModLookupResult.ts │ ├── IModifiers.ts │ ├── INotification.ts │ ├── IPreset.ts │ ├── IState.ts │ ├── ITableAttribute.ts │ ├── ITestResult.ts │ ├── ITool.ts │ ├── SortDirection.ts │ ├── VortexInstallType.ts │ ├── api.ts │ └── collections │ │ ├── IGameSpecificInterfaceProps.ts │ │ └── api.ts ├── util │ ├── AsyncComponent.tsx │ ├── BatchContext.ts │ ├── ComponentEx.ts │ ├── ConcurrencyLimiter.ts │ ├── CustomErrors.ts │ ├── Debouncer.ts │ ├── EpicGamesLauncher.ts │ ├── ExtensionManager.ts │ ├── ExtensionProvider.ts │ ├── GameStoreHelper.ts │ ├── GlobalNotifications.ts │ ├── LazyComponent.tsx │ ├── LevelPersist.ts │ ├── MutexContext.ts │ ├── PresetManager.ts │ ├── ReduxPersistor.ts │ ├── ReduxProp.ts │ ├── ReduxWatcher.ts │ ├── RelaxedReselectCache.ts │ ├── StarterInfo.ts │ ├── Steam.ts │ ├── StyleManager.ts │ ├── SubPersistor.ts │ ├── __mocks__ │ │ ├── ExtensionProvider.ts │ │ └── log.ts │ ├── api.ts │ ├── application.electron.ts │ ├── application.ts │ ├── archives.ts │ ├── asyncRequire.tsx │ ├── bbcode.ts │ ├── bbcode │ │ ├── BrTag.tsx │ │ ├── FontTag.tsx │ │ ├── HeadingTag.tsx │ │ ├── IdentityTag.tsx │ │ ├── LineTag.tsx │ │ ├── LinkTag.tsx │ │ ├── MoreTag.tsx │ │ ├── SizeTag.tsx │ │ ├── SpoilerTag.tsx │ │ ├── StyleTag.tsx │ │ ├── SvgTag.tsx │ │ ├── TooltipTag.tsx │ │ └── YoutubeTag.tsx │ ├── bindProps.ts │ ├── calculateFolderSize.ts │ ├── checksum.ts │ ├── commandLine.ts │ ├── constants.ts │ ├── copyRecursive.ts │ ├── datelocales.ts │ ├── deepMerge.ts │ ├── devel.ts │ ├── electron.ts │ ├── electronRemote.ts │ ├── errorHandling.ts │ ├── estimateSize.ts │ ├── exeIcon.ts │ ├── extensionRequire.ts │ ├── fileValidation.ts │ ├── fs.ts │ ├── fsAtomic.ts │ ├── genHash.ts │ ├── getAttr.ts │ ├── getFileList.ts │ ├── getNormalizeFunc.ts │ ├── getVortexPath.ts │ ├── github.ts │ ├── i18n.ts │ ├── lazyRequire.ts │ ├── libxmljs.ts │ ├── local.ts │ ├── log.ts │ ├── makeCaseInsensitive.ts │ ├── makeReactive.ts │ ├── menu.ts │ ├── message.ts │ ├── migrate.ts │ ├── monkeyPatching.ts │ ├── nativeErrors.ts │ ├── network.ts │ ├── onceCB.ts │ ├── opn.ts │ ├── reduxLogger.ts │ ├── reduxSanity.ts │ ├── relativeTime.ts │ ├── requireRebuild.ts │ ├── requireRemap.ts │ ├── runElevatedCustomTool.ts │ ├── selectors.ts │ ├── smoothScroll.ts │ ├── startupSettings.ts │ ├── store.ts │ ├── storeHelper.ts │ ├── transferPath.ts │ ├── updateStore.ts │ ├── util.ts │ ├── vortex-run │ │ ├── lib │ │ │ ├── elevated.d.ts │ │ │ ├── elevated.js │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ ├── thread.d.ts │ │ │ └── thread.js │ │ ├── package.json │ │ ├── src │ │ │ ├── elevated.ts │ │ │ ├── index.ts │ │ │ └── thread.ts │ │ ├── tsconfig.json │ │ └── yarn.lock │ ├── waitForCondition.ts │ ├── walk.ts │ └── webview.ts ├── validationCode │ ├── IPreset.validate.js │ ├── dummy.js │ └── validation.ts └── views │ ├── DNDContainer.tsx │ ├── Dialog.tsx │ ├── DialogContainer.tsx │ ├── GlobalOverlay.tsx │ ├── LoadingScreen.tsx │ ├── MainFooter.tsx │ ├── MainOverlay.tsx │ ├── MainPage.tsx │ ├── MainPageBody.tsx │ ├── MainPageContainer.tsx │ ├── MainPageHeader.tsx │ ├── MainWindow.tsx │ ├── Notification.tsx │ ├── NotificationButton.tsx │ ├── OverlayContainer.tsx │ ├── PageButton.tsx │ ├── QuickLauncher.tsx │ ├── Settings.tsx │ ├── WindowControls.tsx │ └── api.ts ├── structure.md ├── test-codesigntool.ps1 ├── tools ├── addicons │ ├── index.html │ ├── main.js │ └── renderer.js ├── buildScripts │ └── buildSingleExtension.js ├── editicons.cmd ├── generateicons.js ├── iconconfig.json ├── mdiconfig.json ├── renameicons.js ├── sourcemap.cmd ├── sourcemap │ ├── .vscode │ │ └── tasks.json │ ├── package.json │ ├── src │ │ ├── SourceMap.ts │ │ ├── main.ts │ │ └── translate.ts │ └── tsconfig.json ├── stackmap │ ├── .vscode │ │ ├── extensions.json │ │ ├── launch.json │ │ ├── settings.json │ │ └── tasks.json │ ├── .vscodeignore │ ├── CHANGELOG.md │ ├── README.md │ ├── media │ │ ├── paste-dark.svg │ │ ├── paste-light.svg │ │ ├── version-dark.svg │ │ ├── version-light.svg │ │ └── vortex.png │ ├── package.json │ ├── src │ │ ├── SourceMap.ts │ │ ├── extension.ts │ │ └── test │ │ │ └── index.ts │ ├── tsconfig.json │ ├── tslint.json │ ├── webpack.config.js │ └── yarn.lock └── testfomod │ └── fomod │ └── ModuleConfig.xml ├── tsconfig.json ├── typings.custom ├── bbcode-to-react.d.ts ├── electron-edge.d.ts ├── index.d.ts ├── node-rest-client.d.ts ├── readme.txt ├── redux-devtools-dispatch.d.ts ├── redux-persist.d.ts ├── redux-watcher.d.ts ├── simple-vdf.d.ts └── various-ext.d.ts ├── updateLicenses.js ├── versions.json ├── vortex.bat ├── webpack.main.config.js ├── webpack.renderer.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/react", "@babel/env", "@babel/preset-typescript"], 3 | "plugins": [ 4 | "i18next-extract", 5 | "@babel/proposal-class-properties", 6 | "@babel/proposal-object-rest-spread" 7 | ], 8 | "env": { 9 | "development": { 10 | "presets": [], 11 | "plugins": [ 12 | ] 13 | }, 14 | "production": { 15 | "minified": true, 16 | "presets": ["react-optimize"], 17 | "plugins": [ 18 | ] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | *.d.ts -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Platform (please complete the following information):** 27 | - OS: [e.g. Windows 10] 28 | - Vortex Version [e.g. 0.16.12] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Vortex Forums (Nexus Mods) 4 | url: https://forums.nexusmods.com/forum/4306-vortex-support/ 5 | about: Please ask and answer questions here. 6 | - name: Discord (Nexus Mods) 7 | url: https://discord.gg/nexusmods 8 | about: Please ask and answer questions here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/assets/github_readme_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/.github/assets/github_readme_title.png -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | disturl=https://electronjs.org/headers 2 | target=24.0.0 3 | runtime=electron 4 | arch=x64 5 | target_arch=x64 6 | msvs_version=2022 7 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-viewport/register'; 2 | import '@storybook/addon-a11y/register'; 3 | import '@storybook/addon-knobs/register'; 4 | -------------------------------------------------------------------------------- /.storybook/presets.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '@storybook/addon-docs/react/preset', 3 | ]; 4 | -------------------------------------------------------------------------------- /.storybook/repair.scss: -------------------------------------------------------------------------------- 1 | .info-table { 2 | background-color: white; 3 | } 4 | 5 | .simplebar-content > pre { 6 | background-color: white; 7 | } 8 | 9 | .sb-show-main { 10 | overflow: auto; 11 | } -------------------------------------------------------------------------------- /.storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "es6", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "noImplicitAny": false, 8 | "removeComments": true, 9 | "preserveConstEnums": true, 10 | "rootDir": "../src", 11 | "outDir": "./out", 12 | "inlineSourceMap": true, 13 | "inlineSources": true, 14 | "skipLibCheck": true, 15 | "jsx":"react" 16 | }, 17 | "files": [ 18 | "typings.custom/index.d.ts", 19 | "src/main.ts", 20 | "src/index.ts", 21 | "src/renderer.tsx", 22 | "src/splash.ts", 23 | "src/extensions/index.ts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.vscode/cSpell.json: -------------------------------------------------------------------------------- 1 | // cSpell Settings 2 | { 3 | 4 | // Version of the setting file. Always 0.1 5 | "version": "0.1", 6 | 7 | // language - current active spelling language 8 | "language": "en", 9 | 10 | // words - list of words to be always considered correct 11 | "words": [ 12 | ], 13 | 14 | // flagWords - list of words to be always considered incorrect 15 | // This is useful for offensive words and common spelling errors. 16 | // For example "hte" should be "the" 17 | "flagWords": [ 18 | "hte" 19 | ] 20 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint" 4 | ] 5 | } -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | msvs_version "2022" 2 | child-concurrency 1 3 | -------------------------------------------------------------------------------- /__mocks__/@electron/remote.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getCurrentWindow: jest.fn(() => null), 3 | }; 4 | -------------------------------------------------------------------------------- /__mocks__/diskusage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let checkResult = { 4 | '': { 5 | free: 42, 6 | }, 7 | } 8 | 9 | module.exports = { 10 | check: (checkPath) => { 11 | return checkResult[checkPath] || checkResult['']; 12 | }, 13 | __setCheckResult: (checkPath, res) => { 14 | checkResult[checkPath] = res; 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /__mocks__/electron.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const os = require('os'); 4 | 5 | const dialog = { 6 | showMessageBoxSync: jest.fn(), 7 | showMessageBox: jest.fn(), 8 | showErrorBox: jest.fn(), 9 | getWindow: jest.fn(() => null), 10 | }; 11 | 12 | const app = { 13 | exit: jest.fn(), 14 | getAppPath: jest.fn(() => os.tmpdir()), 15 | getPath: jest.fn(() => os.tmpdir()), 16 | }; 17 | 18 | module.exports = { 19 | require: jest.fn(), 20 | match: jest.fn(), 21 | app, 22 | dialog 23 | }; 24 | -------------------------------------------------------------------------------- /__mocks__/ffi.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | 5 | let error = undefined; 6 | 7 | module.exports = { 8 | Library: (name, exp) => { 9 | let result = {}; 10 | let keys = Object.keys(exp); 11 | for (var i = 0; i < keys.length; ++i) { 12 | result[keys[i]] = { 13 | async: (...args) => { 14 | const callback = args[args.length - 1]; 15 | if (error) { 16 | return callback(new Error(error)); 17 | } 18 | return callback(null, 42); 19 | } 20 | }; 21 | } 22 | return result; 23 | }, 24 | __setError: (err) => { error = err; }, 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /__mocks__/leveldown.js: -------------------------------------------------------------------------------- 1 | module.exports = {} -------------------------------------------------------------------------------- /__mocks__/modmeta-db.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | genHash: () => { 5 | console.log('call genHash'); 6 | return Promise.resolve({ md5sum: 'fake hash' }); 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /__mocks__/original-fs.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | } -------------------------------------------------------------------------------- /__mocks__/react-i18next.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React from 'react'; 4 | 5 | const react_i18n = jest.genMockFromModule('react-i18next'); 6 | 7 | function translate(namespace) { 8 | return (component) => { 9 | return class Translation extends React.Component { 10 | render() { 11 | return React.createElement(component, Object.assign({}, this.props, { 12 | t: (str) => str 13 | }), []); 14 | } 15 | } 16 | } 17 | } 18 | 19 | react_i18n.withTranslation = translate; 20 | 21 | module.exports = react_i18n; 22 | -------------------------------------------------------------------------------- /__mocks__/ref-struct.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function Struct(desc) { 4 | this.ref = () => undefined; 5 | } 6 | 7 | Struct.size = 0; 8 | 9 | module.exports = () => Struct; 10 | -------------------------------------------------------------------------------- /__mocks__/ref-union.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = (desc) => undefined; 4 | -------------------------------------------------------------------------------- /__mocks__/ref.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | types: { 5 | void: { size: 0, indirection: 1 } 6 | }, 7 | refType: (type) => type !== undefined ? type.toString() : '', 8 | coerceType: (type) => type, 9 | alloc: (type) => ({ size: 0 }), 10 | }; 11 | -------------------------------------------------------------------------------- /__mocks__/turbowalk.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let handlers = { 4 | }; 5 | 6 | module.exports = { 7 | __esModule: true, 8 | default: (path, cb) => { 9 | return new Promise((resolve, reject) => { 10 | if (handlers[path] !== undefined) { 11 | handlers[path]((err, files) => { 12 | if (err !== null) { 13 | reject(err); 14 | } else { 15 | cb(files); 16 | resolve(); 17 | } 18 | }) 19 | } else { 20 | cb([]); 21 | resolve(); 22 | } 23 | }); 24 | }, 25 | __setPathHandler: (path, handler) => { 26 | handlers[path] = handler; 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /__mocks__/vortex-api.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../src/index.ts') 2 | -------------------------------------------------------------------------------- /__mocks__/wholocks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let checkResult = []; 4 | 5 | module.exports = { 6 | default: () => { 7 | return checkResult; 8 | }, 9 | __setCheckResult: (res) => { 10 | checkResult = res; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /__mocks__/winapi-bindings.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var path = require('path'); 5 | 6 | let error = undefined; 7 | 8 | module.exports = { 9 | ShellExecuteEx: () => { 10 | if (error === undefined) { 11 | return; 12 | } else { 13 | throw new Error(error); 14 | } 15 | }, 16 | RegGetValue: () => { 17 | return { 18 | type: 'REG_SZ', 19 | value: 'foobar', 20 | }; 21 | }, 22 | GetVolumePathName: (input) => { 23 | const res = path.dirname(input); 24 | if (res === '/missing') { 25 | let err = new Error('fake error'); 26 | err.code = 'ENOTFOUND'; 27 | err.systemCode = 2; 28 | throw err; 29 | } 30 | return res; 31 | }, 32 | __setError: (err) => { error = err; }, 33 | }; 34 | -------------------------------------------------------------------------------- /__tests__/MainWindow.test.jsx: -------------------------------------------------------------------------------- 1 | jest.mock('../src/util/ExtensionProvider'); 2 | 3 | import { MainWindow } from '../src/views/MainWindow'; 4 | import React from 'react'; 5 | import { shallow } from 'enzyme'; 6 | import { findAll } from 'react-shallow-testutils'; 7 | 8 | import { Modal } from 'react-bootstrap'; 9 | 10 | function renderMainWindow() { 11 | function dummyT(input) { 12 | return input; 13 | } 14 | 15 | const api = { events: { on: () => undefined }, getState: () => ({}) }; 16 | 17 | return shallow(); 18 | } 19 | 20 | it('has no modals', () => { 21 | let win = renderMainWindow(); 22 | let modals = findAll(win, (ele) => (ele !== null) && (ele.type === Modal)); 23 | 24 | // expecting only the Dialog Modal 25 | expect(modals.length).toBe(0); 26 | }); 27 | -------------------------------------------------------------------------------- /__tests__/NXMUrl.test.js: -------------------------------------------------------------------------------- 1 | import NXMUrl from '../src/extensions/nexus_integration/NXMUrl'; 2 | 3 | describe('NXMUrl', () => { 4 | it('parses correctly', () => { 5 | const url = new NXMUrl('nxm://Fallout4/mods/123/files/456'); 6 | expect(url.gameId).toBe('Fallout4'); 7 | expect(url.modId).toBe(123); 8 | expect(url.fileId).toBe(456); 9 | }); 10 | it('throws on invalid url', () => { 11 | expect(() => new NXMUrl('gugu')).toThrow(new Error('invalid nxm url "gugu"')); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /__tests__/actions.nexus_integration.test.js: -------------------------------------------------------------------------------- 1 | import * as actions from '../src/extensions/nexus_integration/actions/account'; 2 | 3 | describe('setUserAPIKey', () => { 4 | it('creates the correct action', () => { 5 | expect(actions.setUserAPIKey('apikey')).toEqual({ 6 | error: false, 7 | type: 'SET_USER_API_KEY', 8 | payload: 'apikey' 9 | }); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /__tests__/actions.profile_management.test.js: -------------------------------------------------------------------------------- 1 | import * as actions from '../src/extensions/profile_management/actions/profiles'; 2 | 3 | describe('setModEnabled', () => { 4 | it('creates the correct action', () => { 5 | expect(actions.setModEnabled('profileId1', 'modId1', true)).toEqual({ 6 | error: false, 7 | type: 'SET_MOD_ENABLED', 8 | payload: { profileId: 'profileId1', modId: 'modId1', enable: true }, 9 | }); 10 | }); 11 | }); 12 | 13 | describe('setFeature', () => { 14 | it('creates the correct action', () => { 15 | expect(actions.setFeature('profileId1', 'featureId1', 'test')).toEqual({ 16 | error: false, 17 | type: 'SET_PROFILE_FEATURE', 18 | payload: { profileId: 'profileId1', featureId: 'featureId1', value: 'test' }, 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /__tests__/actions.session.test.js: -------------------------------------------------------------------------------- 1 | import * as actions from '../src/actions/session'; 2 | 3 | describe('displayGroup', () => { 4 | it('generates an action', () => { 5 | expect(actions.displayGroup('groupId', 'itemId')).toEqual({ 6 | error: false, 7 | type: 'DISPLAY_GROUP', 8 | payload: { groupId: 'groupId', itemId: 'itemId' } 9 | }); 10 | }); 11 | }); 12 | 13 | -------------------------------------------------------------------------------- /__tests__/actions.settings_metaserver.test.js: -------------------------------------------------------------------------------- 1 | import * as actions from '../src/extensions/settings_metaserver/actions'; 2 | 3 | describe('addMetaserver', () => { 4 | it('creates the correct action', () => { 5 | expect(actions.addMetaserver('id1', 'url1')).toEqual({ 6 | error: false, 7 | type: 'ADD_METASERVER', 8 | payload: { id: 'id1', url: 'url1' }, 9 | }); 10 | }); 11 | }); 12 | 13 | describe('removeMetaserver', () => { 14 | it('creates the correct action', () => { 15 | expect(actions.removeMetaserver('id1', 86400)).toEqual({ 16 | error: false, 17 | type: 'REMOVE_METASERVER', 18 | payload: { id: 'id1', cacheDurationSec: 86400 }, 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /__tests__/actions.starter_dashlet.test.js: -------------------------------------------------------------------------------- 1 | import * as actions from '../src/extensions/starter_dashlet/actions'; 2 | 3 | describe('setPrimaryTool', () => { 4 | it('sets the Primary Tool', () => { 5 | expect(actions.setPrimaryTool('gameId1', 'value')).toEqual({ 6 | error: false, 7 | type: 'SET_PRIMARY_TOOL', 8 | payload: { gameId: 'gameId1', toolId: 'value' }, 9 | }); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /__tests__/actions.updater.test.js: -------------------------------------------------------------------------------- 1 | import * as actions from '../src/extensions/updater/actions'; 2 | 3 | describe('setUpdateChannel', () => { 4 | it('sets the Update Channel', () => { 5 | expect(actions.setUpdateChannel('new value')).toEqual({ 6 | error: false, 7 | type: 'SET_UPDATE_CHANNEL', 8 | payload: 'new value' , 9 | }); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /__tests__/getAttr.test.js: -------------------------------------------------------------------------------- 1 | import getAttr from '../src/util/getAttr'; 2 | 3 | describe('getAttr', () => { 4 | it('returns default on undefined dict', () => { 5 | expect(getAttr(undefined, 'answer', 42)).toBe(42); 6 | }); 7 | 8 | it('returns default on null dict', () => { 9 | expect(getAttr(null, 'answer', 42)).toBe(42); 10 | }); 11 | 12 | it('returns default if key is missing', () => { 13 | expect(getAttr({ wrong: 43 }, 'answer', 42)).toBe(42); 14 | }); 15 | 16 | it('returns value if key exists', () => { 17 | expect(getAttr({ wrong: 43 }, 'wrong', 42)).toBe(43); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /__tests__/reducer.session.test.js: -------------------------------------------------------------------------------- 1 | import { sessionReducer } from '../src/reducers/session'; 2 | 3 | describe('displayGroup', () => { 4 | it('sets the display item and creates missing nodes', () => { 5 | let input = { }; 6 | let result = sessionReducer.reducers.DISPLAY_GROUP(input, { groupId: 'someGroupId', itemId: 'someItemId' }); 7 | expect(result.displayGroups).toEqual({ someGroupId: 'someItemId' }); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /__tests__/reducers.firststeps_dashlet.test.js: -------------------------------------------------------------------------------- 1 | import settingsReducer from '../src/extensions/firststeps_dashlet/reducers'; 2 | 3 | describe('dismissStep', () => { 4 | it('dismisses a todo message from the "first steps" list', () => { 5 | let input = { steps: {stepId1: true}}; 6 | let result = settingsReducer.reducers.DISMISS_STEP(input, 'stepId1'); 7 | expect(result).toEqual({ steps: {stepId1: true}}); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /__tests__/reducers.nexus_integration.test.js: -------------------------------------------------------------------------------- 1 | import { accountReducer } from '../src/extensions/nexus_integration/reducers/account'; 2 | 3 | describe('setUserAPIKey', () => { 4 | it('sets the key', () => { 5 | let input = { }; 6 | let result = accountReducer.reducers.SET_USER_API_KEY(input, 'key'); 7 | expect(result.APIKey).toBe('key'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /__tests__/reducers.settings_metaserver.test.js: -------------------------------------------------------------------------------- 1 | import settingsReducer from '../src/extensions/settings_metaserver/reducers'; 2 | 3 | describe('addMetaserver', () => { 4 | it('adds a Metaserver', () => { 5 | let input = { servers: {id1: { url1: 'url', cacheDurationSec: 86400, priority: 1 } }}; 6 | let result = settingsReducer.reducers.ADD_METASERVER(input, { id: 'id1', url: 'new url' }); 7 | expect(result).toEqual({ servers: {id1: { url: 'new url', cacheDurationSec: 86400, priority: 1 } }}); 8 | }); 9 | }); 10 | 11 | describe('removeMetaserver', () => { 12 | it('removes a Metaserver', () => { 13 | let input = { servers: {id1: {} } }; 14 | let result = settingsReducer.reducers.REMOVE_METASERVER(input, { id: 'id1', cacheDurationSec: 86400 }); 15 | expect(result).toEqual({servers: {} }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /__tests__/reducers.updater.test.js: -------------------------------------------------------------------------------- 1 | import reducer from '../src/extensions/updater/reducers'; 2 | 3 | describe('setUpdateChannel', () => { 4 | it('sets the Update Channel', () => { 5 | let input = { channel: 'value' }; 6 | let result = reducer.reducers.SET_UPDATE_CHANNEL(input, 'new value' ); 7 | expect(result).toEqual({ channel: 'new value' }); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | *.js.map 3 | node_modules 4 | actions 5 | assets 6 | games 7 | lib 8 | locales 9 | reducers 10 | index.html 11 | splash.html 12 | 7z.exe 13 | LICENSE.md 14 | -------------------------------------------------------------------------------- /app/.yarnclean: -------------------------------------------------------------------------------- 1 | # test directories 2 | __tests__ 3 | test 4 | tests 5 | powered-test 6 | 7 | # asset directories 8 | docs 9 | doc 10 | website 11 | images 12 | assets 13 | 14 | # examples 15 | example 16 | examples 17 | 18 | # code coverage directories 19 | coverage 20 | .nyc_output 21 | 22 | # build scripts 23 | Makefile 24 | Gulpfile.js 25 | Gruntfile.js 26 | 27 | # configs 28 | appveyor.yml 29 | circle.yml 30 | codeship-services.yml 31 | codeship-steps.yml 32 | wercker.yml 33 | .tern-project 34 | .gitattributes 35 | .editorconfig 36 | .*ignore 37 | .eslintrc 38 | .jshintrc 39 | .flowconfig 40 | .documentup.json 41 | .yarn-metadata.json 42 | .travis.yml 43 | 44 | # misc 45 | *.md 46 | -------------------------------------------------------------------------------- /assets/dotnetprobe.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/dotnetprobe.exe -------------------------------------------------------------------------------- /assets/fonts/Inter-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-Black.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-BlackItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-BoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-ExtraLight.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-Italic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-LightItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-MediumItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-SemiBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-Thin.ttf -------------------------------------------------------------------------------- /assets/fonts/Inter-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Inter-ThinItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-Black.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-BlackItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-BoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-ExtraBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-ExtraLight.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-Italic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-LightItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-MediumItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-SemiBold.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-Thin.ttf -------------------------------------------------------------------------------- /assets/fonts/Montserrat-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Montserrat-ThinItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /assets/fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /assets/images/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/Thumbs.db -------------------------------------------------------------------------------- /assets/images/ad-banner-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/ad-banner-large.png -------------------------------------------------------------------------------- /assets/images/ad-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/ad-banner.png -------------------------------------------------------------------------------- /assets/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/bg.png -------------------------------------------------------------------------------- /assets/images/dashlets/add-game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/dashlets/add-game.png -------------------------------------------------------------------------------- /assets/images/dashlets/add-mods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/dashlets/add-mods.png -------------------------------------------------------------------------------- /assets/images/dashlets/install-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/dashlets/install-tools.png -------------------------------------------------------------------------------- /assets/images/dashlets/login-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/dashlets/login-link.png -------------------------------------------------------------------------------- /assets/images/license_nucleo.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) Amber Creative Lab Ltd 2 | 3 | Version 1, 2 July 2018 4 | 5 | Nucleo Icons 6 | 7 | https://nucleoapp.com/ 8 | 9 | The Nucleo icons are copyrighted. Redistribution is not permitted. Use in source and binary forms, with or without modification, is permitted only if you possess a Nucleo icons license. 10 | 11 | Please refer to the license for additional information https://nucleoapp.com/license -------------------------------------------------------------------------------- /assets/images/log-in-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/log-in-bg.png -------------------------------------------------------------------------------- /assets/images/noavatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/noavatar.png -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/splash.png -------------------------------------------------------------------------------- /assets/images/splash_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/splash_old.png -------------------------------------------------------------------------------- /assets/images/vortex.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/vortex.ico -------------------------------------------------------------------------------- /assets/images/vortex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/images/vortex.png -------------------------------------------------------------------------------- /assets/licenses/ISC.md: -------------------------------------------------------------------------------- 1 | Internet Systems Consortium license 2 | =================================== 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any purpose 5 | with or without fee is hereby granted, provided that the above copyright notice 6 | and this permission notice appear in all copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 10 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 12 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 13 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 14 | THIS SOFTWARE. 15 | -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-console-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-console-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-datetime-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-datetime-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-debug-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-debug-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-errorhandling-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-errorhandling-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-file-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-file-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-file-l1-2-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-file-l1-2-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-file-l2-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-file-l2-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-handle-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-handle-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-heap-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-heap-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-interlocked-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-interlocked-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-libraryloader-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-libraryloader-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-localization-l1-2-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-localization-l1-2-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-memory-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-memory-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-namedpipe-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-namedpipe-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-processenvironment-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-processenvironment-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-processthreads-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-processthreads-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-processthreads-l1-1-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-processthreads-l1-1-1.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-profile-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-profile-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-rtlsupport-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-rtlsupport-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-string-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-string-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-synch-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-synch-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-synch-l1-2-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-synch-l1-2-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-sysinfo-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-sysinfo-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-timezone-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-timezone-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-core-util-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-core-util-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-conio-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-conio-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-convert-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-convert-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-environment-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-environment-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-filesystem-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-filesystem-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-heap-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-heap-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-locale-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-locale-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-math-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-math-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-multibyte-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-multibyte-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-private-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-private-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-process-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-process-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-runtime-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-runtime-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-stdio-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-stdio-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-string-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-string-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-time-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-time-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/api-ms-win-crt-utility-l1-1-0.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/api-ms-win-crt-utility-l1-1-0.dll -------------------------------------------------------------------------------- /assets/vcruntime/concrt140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/concrt140.dll -------------------------------------------------------------------------------- /assets/vcruntime/msvcp140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/msvcp140.dll -------------------------------------------------------------------------------- /assets/vcruntime/msvcp140_1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/msvcp140_1.dll -------------------------------------------------------------------------------- /assets/vcruntime/msvcp140_2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/msvcp140_2.dll -------------------------------------------------------------------------------- /assets/vcruntime/msvcp140_atomic_wait.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/msvcp140_atomic_wait.dll -------------------------------------------------------------------------------- /assets/vcruntime/msvcp140_codecvt_ids.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/msvcp140_codecvt_ids.dll -------------------------------------------------------------------------------- /assets/vcruntime/ucrtbase.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/ucrtbase.dll -------------------------------------------------------------------------------- /assets/vcruntime/vcamp140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/vcamp140.dll -------------------------------------------------------------------------------- /assets/vcruntime/vccorlib140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/vccorlib140.dll -------------------------------------------------------------------------------- /assets/vcruntime/vcomp140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/vcomp140.dll -------------------------------------------------------------------------------- /assets/vcruntime/vcruntime140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/vcruntime140.dll -------------------------------------------------------------------------------- /assets/vcruntime/vcruntime140_1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/assets/vcruntime/vcruntime140_1.dll -------------------------------------------------------------------------------- /build/amd64-unicode/AccessControl.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/build/amd64-unicode/AccessControl.dll -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/build/icon.ico -------------------------------------------------------------------------------- /build/installerSidebar.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/build/installerSidebar.bmp -------------------------------------------------------------------------------- /build/x86-ansi/AccessControl.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/build/x86-ansi/AccessControl.dll -------------------------------------------------------------------------------- /build/x86-unicode/AccessControl.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/build/x86-unicode/AccessControl.dll -------------------------------------------------------------------------------- /copy_sourcemaps.js: -------------------------------------------------------------------------------- 1 | const copyfiles = require('copyfiles'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const pack = JSON.parse(fs.readFileSync(path.join('app', 'package.json'))); 6 | 7 | copyfiles(['app/**/*.js.map', 'app/**/*.js', `sourcemaps/${pack.version}`], {up: 1}, () => { 8 | console.log('done'); 9 | }); -------------------------------------------------------------------------------- /dev-app-update.yml: -------------------------------------------------------------------------------- 1 | owner: Nexus-Mods 2 | repo: Vortex 3 | provider: github 4 | private: false 5 | publisherName: 6 | - Black Tree Gaming Ltd 7 | - Black Tree Gaming Limited 8 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "allowSyntheticDefaultImports": true 6 | }, 7 | "exclude": [ 8 | "node_modules" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /licenseFormat.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "version": "", 4 | "licenses": "", 5 | "repository": "", 6 | "licenseText": false 7 | } 8 | -------------------------------------------------------------------------------- /samples/sample-extension/src/index.ts: -------------------------------------------------------------------------------- 1 | import { types } from 'vortex-api'; 2 | 3 | function main(context: types.IExtensionContext) { 4 | context.registerAction('global-icons', 100, 'menu', {}, 'Sample', () => { 5 | context.api.showDialog('info', 'Success!', { 6 | text: 'Hello World', 7 | }, [ 8 | { label: 'Close' }, 9 | ]); 10 | }); 11 | return true; 12 | } 13 | 14 | export default main; 15 | -------------------------------------------------------------------------------- /samples/sample-extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "noImplicitAny": false, 7 | "removeComments": true, 8 | "preserveConstEnums": true, 9 | "rootDir": "./src", 10 | "outDir": "./out", 11 | "jsx": "react", 12 | "skipLibCheck": true, 13 | "esModuleInterop": true, 14 | "sourceMap": false 15 | }, 16 | "exclude": [ 17 | "node_modules" 18 | ], 19 | "files": [ 20 | "src/index.ts" 21 | ] 22 | } -------------------------------------------------------------------------------- /samples/sample-extension/webpack.config.js: -------------------------------------------------------------------------------- 1 | let webpack = require('vortex-api/bin/webpack').default; 2 | 3 | module.exports = webpack('sample-extension', __dirname, 5); 4 | 5 | -------------------------------------------------------------------------------- /setupTests.js: -------------------------------------------------------------------------------- 1 | import 'regenerator-runtime/runtime'; 2 | import { configure } from 'enzyme'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | 5 | configure({ adapter: new Adapter() }); 6 | -------------------------------------------------------------------------------- /src/actions/notificationSettings.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from './safeCreateAction'; 2 | 3 | /** 4 | * set (or unset) notifications to not show again 5 | */ 6 | export const suppressNotification = safeCreateAction('SUPPRESS_NOTIFICATION', 7 | (id: string, suppress: boolean) => ({ id, suppress })); 8 | 9 | export const resetSuppression = safeCreateAction('RESET_SUPPRESSION', () => null); 10 | -------------------------------------------------------------------------------- /src/actions/user.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from './safeCreateAction'; 2 | 3 | export const setMultiUser = safeCreateAction('SET_MUTLI_USER', (enabled: boolean) => enabled); 4 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const HTTP_HEADER_SIZE: number = 16384; 2 | export const DEBUG_PORT: string = '9222'; 3 | 4 | export const VCREDIST_URL: string = 'https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist'; 5 | -------------------------------------------------------------------------------- /src/controls/Dashlet.tsx: -------------------------------------------------------------------------------- 1 | import { truthy } from '../util/util'; 2 | 3 | import * as React from 'react'; 4 | 5 | export interface IDashletProps { 6 | className: string; 7 | title: string; 8 | } 9 | 10 | class Dashlet extends React.Component { 11 | public render(): JSX.Element { 12 | const { className, title } = this.props; 13 | const classes = ['dashlet'].concat(className.split(' ')); 14 | return ( 15 |
16 | {truthy(title) ?
{title}
: null} 17 | {this.props.children} 18 |
19 | ); 20 | } 21 | } 22 | 23 | export default Dashlet; 24 | -------------------------------------------------------------------------------- /src/controls/IconBar.unfinished_stories.js: -------------------------------------------------------------------------------- 1 | import { withInfo } from "@storybook/addon-info"; 2 | import { withKnobs } from '@storybook/addon-knobs'; 3 | import React from 'react'; 4 | import IconBase from './IconBase'; 5 | import IconBar from './IconBar'; 6 | 7 | const sets = { 8 | icons: new Set(['sample', 'spinner']), 9 | }; 10 | 11 | function getSet(set) { 12 | return Promise.resolve(sets[set]); 13 | } 14 | 15 | function Icon(props) { 16 | return ; 17 | } 18 | 19 | export default { 20 | title: 'IconBar', 21 | parameters: { 22 | componentSubtitle: 'Control containing multiple buttons', 23 | decorators: [withInfo, withKnobs], 24 | info: { 25 | inline: true, 26 | } 27 | } 28 | }; 29 | 30 | export const simple = () => ( 31 | 34 | ); 35 | -------------------------------------------------------------------------------- /src/controls/Spinner.tsx: -------------------------------------------------------------------------------- 1 | import Icon from './Icon'; 2 | 3 | import * as React from 'react'; 4 | 5 | export interface ISpinnerProps { 6 | style?: React.CSSProperties; 7 | className?: string; 8 | } 9 | 10 | function Spinner(props: ISpinnerProps) { 11 | return ; 12 | } 13 | 14 | export default Spinner; 15 | -------------------------------------------------------------------------------- /src/controls/Step.tsx: -------------------------------------------------------------------------------- 1 | import Icon from './Icon'; 2 | 3 | import * as React from 'react'; 4 | 5 | export interface IStepProps { 6 | stepId: string; 7 | title: string; 8 | description: string; 9 | index?: number; 10 | state?: 'done' | 'current' | 'future'; 11 | } 12 | 13 | class Step extends React.Component { 14 | public render(): JSX.Element { 15 | const { description, index, state, title } = this.props; 16 | return ( 17 |
18 |
19 | {state === 'done' ? : index + 1} 20 |
21 |
22 |
{title}
23 |
24 |
25 | ); 26 | } 27 | } 28 | 29 | export default Step; 30 | -------------------------------------------------------------------------------- /src/controls/constants.ts: -------------------------------------------------------------------------------- 1 | // name to be displayed for extension downloads 2 | export const SITE_GAME_NAME = 'Tools & Extensions'; 3 | 4 | // delay for hover effects (e.g. submenus opening on hover) that would otherwise 5 | // be frustrating or irritating 6 | export const HOVER_DELAY = 500; 7 | -------------------------------------------------------------------------------- /src/extensions/about_dialog/index.ts: -------------------------------------------------------------------------------- 1 | import { IExtensionContext } from '../../types/IExtensionContext'; 2 | 3 | import AboutPage from './views/AboutPage'; 4 | 5 | function init(context: IExtensionContext): boolean { 6 | context.registerAction('global-icons', 200, 'about', {}, 'About', () => { 7 | context.api.events.emit('show-main-page', 'About'); 8 | }); 9 | 10 | context.registerMainPage('', 'About', AboutPage, { group: 'hidden' }); 11 | 12 | return true; 13 | } 14 | 15 | export default init; 16 | -------------------------------------------------------------------------------- /src/extensions/about_dialog/types/ILicense.ts: -------------------------------------------------------------------------------- 1 | export interface ILicense { 2 | key?: string; 3 | name: string; 4 | version: string; 5 | description: string; 6 | licenses: string | string[]; 7 | repository: string; 8 | publisher: string; 9 | email?: string; 10 | url?: string; 11 | licenseFile?: string; 12 | licenseModified?: 'yes' | 'no'; 13 | } 14 | -------------------------------------------------------------------------------- /src/extensions/analytics/actions/analytics.action.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | /** 6 | * changes the 'analytics' toggle, which is either on or off 7 | */ 8 | export const setAnalytics = safeCreateAction('SET_UPDATE_ANALYTICS', analytics => analytics); 9 | -------------------------------------------------------------------------------- /src/extensions/analytics/constants.ts: -------------------------------------------------------------------------------- 1 | export const HELP_ARTICLE = 'https://help.nexusmods.com/article/121-diagnostics-usage-data-vortex'; 2 | 3 | export const GA4_STABLE_MEASUREMENT_ID = process.env['GA4_STABLE_MEASUREMENT_ID'] || 'G-EK37QBX22N'; 4 | export const GA4_BETA_MEASUREMENT_ID = process.env['GA4_BETA_MEASUREMENT_ID'] || 'G-XJZD1ML5D6'; 5 | export const GA4_NEXT_MEASUREMENT_ID = process.env['GA4_NEXT_MEASUREMENT_ID'] || 'G-958SX4ZHJL'; -------------------------------------------------------------------------------- /src/extensions/analytics/ga4mp/README.md: -------------------------------------------------------------------------------- 1 | We are using `ga4mp.esm.js` from https://ga4mp.dev/ directly and not installed via yarn/npm as Electron isn't playing nice with the ESM module and it won't import. It doesn't ship with a commonjs build even though it claims it does and ikt's pacage.json is broken as of 0.0.4. 2 | 3 | This is primarily for testing at this point alongside our older UA analytics so we can work out if to invest time in forking and iterating on this project or to move to a different analytics solution. -------------------------------------------------------------------------------- /src/extensions/analytics/reducers/settings.reducer.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | 3 | import { setAnalytics } from '../actions/analytics.action'; 4 | 5 | import update from 'immutability-helper'; 6 | 7 | /** 8 | * reducer for changes to interface settings 9 | */ 10 | const settingsReducer: IReducerSpec = { 11 | reducers: { 12 | [setAnalytics as any]: (state, payload) => update(state, { enabled: { $set: payload } }), 13 | }, 14 | defaults: { 15 | enabled: undefined, // TODO, set me to false 16 | }, 17 | }; 18 | 19 | export default settingsReducer; 20 | -------------------------------------------------------------------------------- /src/extensions/analytics/types.ts: -------------------------------------------------------------------------------- 1 | export type StateListeners = Array<{ path: string[], callback: (previous, current) => void }>; 2 | export type EventListeners = Array<{ event: string, callback: (event) => void }>; 3 | -------------------------------------------------------------------------------- /src/extensions/announcement_dashlet/actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-act'; 2 | import { IAnnouncement, ISurveyInstance } from './types'; 3 | 4 | export const setAnnouncements = createAction('SET_ANNOUNCEMENTS', 5 | (announcements: IAnnouncement[]) => announcements); 6 | 7 | export const setAvailableSurveys = createAction('SET_AVAILABLE_SURVEYS', 8 | (surveys: ISurveyInstance[]) => surveys); 9 | 10 | export const setSuppressSurvey = createAction('SET_SUPPRESS_SURVEY', 11 | (id: string, suppress: boolean) => ({ id, suppress })); 12 | -------------------------------------------------------------------------------- /src/extensions/announcement_dashlet/reducers/announcements.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { setSafe } from '../../../util/storeHelper'; 3 | 4 | import * as actions from '../actions'; 5 | 6 | const sessionReducer: IReducerSpec = { 7 | reducers: { 8 | [actions.setAnnouncements as any]: (state, payload) => 9 | setSafe(state, ['announcements'], payload), 10 | }, 11 | defaults: { 12 | announcements: [], 13 | }, 14 | }; 15 | 16 | export default sessionReducer; 17 | -------------------------------------------------------------------------------- /src/extensions/announcement_dashlet/reducers/persistent.ts: -------------------------------------------------------------------------------- 1 | import * as _ from 'lodash'; 2 | import { IReducerSpec } from '../../../types/IExtensionContext'; 3 | import { setSafe } from '../../../util/storeHelper'; 4 | 5 | import * as actions from '../actions'; 6 | 7 | const persistentReducer: IReducerSpec = { 8 | reducers: { 9 | [actions.setSuppressSurvey as any]: (state, payload) => 10 | setSafe(state, ['suppressed', payload.id], payload.suppress), 11 | }, 12 | defaults: { 13 | }, 14 | }; 15 | 16 | export default persistentReducer; 17 | -------------------------------------------------------------------------------- /src/extensions/announcement_dashlet/reducers/surveys.ts: -------------------------------------------------------------------------------- 1 | import * as _ from 'lodash'; 2 | import { IReducerSpec } from '../../../types/IExtensionContext'; 3 | import { setSafe } from '../../../util/storeHelper'; 4 | 5 | import * as actions from '../actions'; 6 | 7 | const surveySessionReducer: IReducerSpec = { 8 | reducers: { 9 | [actions.setAvailableSurveys as any]: (state, payload) => 10 | setSafe(state, ['available'], payload), 11 | }, 12 | defaults: { 13 | }, 14 | }; 15 | 16 | export default surveySessionReducer; 17 | -------------------------------------------------------------------------------- /src/extensions/browser/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | import { Action } from 'redux'; 4 | import { ThunkAction } from 'redux-thunk'; 5 | 6 | type ShowUrlFunc = (url: string, instructions?: string, subscriber?: string, skippable?: boolean) 7 | => Action<{ url: string, instructions: string, subscriber: string, skippable: boolean }>; 8 | 9 | export const showURL: ShowUrlFunc = 10 | safeCreateAction('SHOW_URL', 11 | (url: string, instructions?: string, subscriber?: string, skippable?: boolean) => 12 | ({ url, instructions, subscriber, skippable: skippable ?? false })) as any; 13 | 14 | export const closeBrowser = safeCreateAction('CLOSE_BROWSER'); 15 | -------------------------------------------------------------------------------- /src/extensions/browser/reducers.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../types/IExtensionContext'; 2 | import { merge, setSafe } from '../../util/storeHelper'; 3 | 4 | import * as actions from './actions'; 5 | 6 | /** 7 | * reducer for changes to ephemeral session state 8 | */ 9 | export const sessionReducer: IReducerSpec = { 10 | reducers: { 11 | [actions.showURL as any]: (state, payload) => { 12 | const { url, instructions, subscriber, skippable } = payload; 13 | return merge(state, [], { url, instructions, subscriber, skippable }); 14 | }, 15 | [actions.closeBrowser as any]: (state, payload) => 16 | setSafe(state, ['url'], undefined), 17 | }, 18 | defaults: { 19 | url: undefined, 20 | instructions: undefined, 21 | subscriber: undefined, 22 | skippable: undefined, 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /src/extensions/browser/types.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nexus-Mods/Vortex/de0c8b7d78101abe2626099ca8cd0dae33689134/src/extensions/browser/types.ts -------------------------------------------------------------------------------- /src/extensions/category_management/actions/session.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | export const showCategoriesDialog = safeCreateAction('SHOW_CATEGORIES_DIALOG', show => show); 6 | -------------------------------------------------------------------------------- /src/extensions/category_management/reducers/session.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import {setSafe} from '../../../util/storeHelper'; 3 | 4 | import * as actions from '../actions/session'; 5 | 6 | /** 7 | * reducer for changes to ephemeral session state 8 | */ 9 | export const sessionReducer: IReducerSpec = { 10 | reducers: { 11 | [actions.showCategoriesDialog as any]: (state, payload) => 12 | setSafe(state, [ 'showDialog' ], payload), 13 | }, 14 | defaults: { 15 | showDialog: false, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /src/extensions/category_management/selectors.ts: -------------------------------------------------------------------------------- 1 | import { activeGameId } from '../../util/selectors'; 2 | 3 | export function allCategories(state: any) { 4 | const gameMode = activeGameId(state); 5 | const categories = state.persistent.categories[gameMode]; 6 | return categories !== undefined ? categories : []; 7 | } 8 | -------------------------------------------------------------------------------- /src/extensions/category_management/types/ICategoryDictionary.ts: -------------------------------------------------------------------------------- 1 | export interface ICategory { 2 | name: string; 3 | parentCategory: string; 4 | order: number; 5 | } 6 | 7 | export interface ICategoryDictionary { 8 | [id: string]: ICategory; 9 | } 10 | -------------------------------------------------------------------------------- /src/extensions/category_management/types/ITrees.ts: -------------------------------------------------------------------------------- 1 | import { TreeItem } from 'react-sortable-tree'; 2 | 3 | export interface ICategoriesTree extends TreeItem { 4 | categoryId: string; 5 | expanded: boolean; 6 | parentId: string; 7 | subtitle: string; 8 | title: string; 9 | order: number; 10 | modCount: number; 11 | children: ICategoriesTree[]; 12 | } 13 | -------------------------------------------------------------------------------- /src/extensions/dashboard/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | export const setLayout = safeCreateAction('SET_LAYOUT', layout => layout); 4 | 5 | export const setDashletEnabled = safeCreateAction('SET_WIDGET_ENABLED', 6 | (widgetId: string, enabled: boolean) => ({ widgetId, enabled })); 7 | 8 | export const setDashletWidth = safeCreateAction('SET_WIDGET_WIDTH', 9 | (widgetId: string, width: number) => ({ widgetId, width })); 10 | 11 | export const setDashletHeight = safeCreateAction('SET_WIDGET_HEIGHT', 12 | (widgetId: string, height: number) => ({ widgetId, height })); 13 | -------------------------------------------------------------------------------- /src/extensions/dashboard/types/IDashletProps.ts: -------------------------------------------------------------------------------- 1 | import {PropsCallback} from '../../../types/IExtensionContext'; 2 | 3 | export interface IDashletProps { 4 | title: string; 5 | width: 1 | 2 | 3; 6 | height: 1 | 2 | 3 | 4 | 5; 7 | position: number; 8 | component: React.ComponentClass; 9 | props?: PropsCallback; 10 | isVisible?: (state: any) => boolean; 11 | fixed: boolean; 12 | closable: boolean; 13 | } 14 | -------------------------------------------------------------------------------- /src/extensions/diagnostics_files/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import { setDialogVisible } from '../../actions/session'; 3 | import { IExtensionContext } from '../../types/IExtensionContext'; 4 | 5 | import DiagnosticsFilesDialog from './views/DiagnosticsFilesDialog'; 6 | 7 | function init(context: IExtensionContext): boolean { 8 | context.registerAction('global-icons', 190, 'bug', {}, 'Diagnostics Files', 9 | () => { context.api.store.dispatch(setDialogVisible('diagnostics-files-dialog')); }); 10 | 11 | context.registerDialog('diagnostics-files-dialog', DiagnosticsFilesDialog); 12 | 13 | return true; 14 | } 15 | 16 | export default init; 17 | -------------------------------------------------------------------------------- /src/extensions/diagnostics_files/types/ISession.ts: -------------------------------------------------------------------------------- 1 | import {LogLevel} from '../../../util/log'; 2 | 3 | export interface ISession { 4 | from: Date; 5 | to: Date; 6 | logs: ILog[]; 7 | } 8 | 9 | export interface ILog { 10 | lineno: number; 11 | time: string; 12 | text: string; 13 | type: LogLevel; 14 | } 15 | -------------------------------------------------------------------------------- /src/extensions/download_management/actions/settings.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | export const setMaxDownloads = safeCreateAction('SET_MAX_DOWNLOADS', max => max); 6 | export const setDownloadPath = safeCreateAction('SET_DOWNLOAD_PATH', dlPath => dlPath); 7 | export const setShowDLDropzone = safeCreateAction('SET_SHOW_DL_DROPZONE', show => show); 8 | export const setShowDLGraph = safeCreateAction('SET_SHOW_DL_GRAPH', show => show); 9 | export const setCopyOnIFF = safeCreateAction('SET_COPY_ON_IFF', enabled => enabled); 10 | export const setMaxBandwidth = safeCreateAction('SET_MAX_BANDWIDTH', bandwidth => bandwidth); 11 | export const setCollectionConcurrency = safeCreateAction('SET_COLLECTION_INSTALL_DOWNLOAD_CONCURRENCY', enabled => enabled); 12 | -------------------------------------------------------------------------------- /src/extensions/download_management/actions/transactions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | /** 4 | * Used to track transfer attempts and correctly recover if it gets interrupted. 5 | */ 6 | export const setTransferDownloads = safeCreateAction('SET_TRANSFER_DOWNLOADS', 7 | (destination: string) => ({ destination })); 8 | -------------------------------------------------------------------------------- /src/extensions/download_management/reducers/transactions.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { deleteOrNop, setSafe } from '../../../util/storeHelper'; 3 | import * as actions from '../actions/transactions'; 4 | 5 | export const transactionsReducer: IReducerSpec = { 6 | reducers: { 7 | [actions.setTransferDownloads as any]: (state, payload) => { 8 | const { destination } = payload; 9 | return ((destination === undefined) || (destination === '')) 10 | ? deleteOrNop(state, ['transfer', 'downloads']) 11 | : setSafe(state, ['transfer', 'downloads'], destination); 12 | }, 13 | }, 14 | defaults: { 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /src/extensions/download_management/types/IChunk.ts: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | 3 | export interface IChunk { 4 | url: () => Promise; 5 | received: number; 6 | offset: number; 7 | size: number; 8 | } 9 | -------------------------------------------------------------------------------- /src/extensions/download_management/types/IDownloadJob.ts: -------------------------------------------------------------------------------- 1 | import { IChunk } from './IChunk'; 2 | import { IDownloadOptions } from './IDownload'; 3 | 4 | import Promise from 'bluebird'; 5 | 6 | export interface IDownloadJob extends IChunk { 7 | state: 'init' | 'running' | 'paused' | 'finished'; 8 | workerId?: number; 9 | options: IDownloadOptions; 10 | confirmedReceived: number; 11 | confirmedOffset: number; 12 | confirmedSize: number; 13 | extraCookies: string[]; 14 | 15 | dataCB?: (offset: number, data) => Promise; 16 | completionCB?: () => void; 17 | errorCB?: (err) => void; 18 | responseCB?: (size: number, fileName: string, chunkable: boolean) => void; 19 | } 20 | -------------------------------------------------------------------------------- /src/extensions/download_management/types/IDownloadResult.ts: -------------------------------------------------------------------------------- 1 | import { IChunk } from './IChunk'; 2 | 3 | export interface IDownloadResult { 4 | filePath: string; 5 | headers: any; 6 | unfinishedChunks: IChunk[]; 7 | hadErrors: boolean; 8 | size: number; 9 | metaInfo: any; 10 | } 11 | -------------------------------------------------------------------------------- /src/extensions/download_management/types/ProgressCallback.ts: -------------------------------------------------------------------------------- 1 | import {IChunk} from './IChunk'; 2 | 3 | export type ProgressCallback = (received: number, total: number, 4 | chunks: IChunk[], chunkable: boolean, 5 | urls: string[], filePath?: string) => void; 6 | -------------------------------------------------------------------------------- /src/extensions/download_management/types/ProtocolHandlers.ts: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | 3 | export interface IResolvedURL { 4 | urls: string[]; 5 | updatedUrl?: string; 6 | meta: any; 7 | } 8 | 9 | export interface IResolvedURLs { 10 | urls: string[]; 11 | updatedUrls?: string[]; 12 | meta: any; 13 | } 14 | 15 | export interface IProtocolHandlers { 16 | [schema: string]: (inputUrl: string, name: string, friendlyName: string) 17 | => Promise; 18 | } 19 | -------------------------------------------------------------------------------- /src/extensions/download_management/util/getDownloadGames.ts: -------------------------------------------------------------------------------- 1 | import { log } from '../../../util/log'; 2 | import { IDownload } from '../types/IDownload'; 3 | 4 | function getDownloadGames(download: IDownload): string[] { 5 | if (Array.isArray(download.game)) { 6 | return download.game; 7 | } else if (download.game === undefined) { 8 | log('warn', 'download with no game associated', JSON.stringify(download)); 9 | return []; 10 | } else { 11 | return [download.game]; 12 | } 13 | } 14 | 15 | export default getDownloadGames; 16 | -------------------------------------------------------------------------------- /src/extensions/extension_manager/actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-act'; 2 | import { IAvailableExtension, IExtension } from './types'; 3 | import { IExtensionOptional } from '../../types/api'; 4 | 5 | export const setAvailableExtensions = createAction('SET_AVAILABLE_EXTENSIONS', 6 | (extensions: IAvailableExtension[]) => extensions); 7 | 8 | export const setInstalledExtensions = createAction('SET_INSTALLED_EXTENSIONS', 9 | (extensions: { [extId: string]: IExtension }) => extensions); 10 | 11 | export const setExtensionsUpdate = createAction('SET_EXTENSIONS_UPDATE_TIME', 12 | (time: number) => time); 13 | 14 | export const setOptionalExtensions = createAction('SET_OPTIONAL_EXTENSIONS', 15 | (optional: { [extId: string]: IExtensionOptional[] }) => optional); -------------------------------------------------------------------------------- /src/extensions/file_based_loadorder/actions/loadOrder.ts: -------------------------------------------------------------------------------- 1 | import createAction from '../../../actions/safeCreateAction'; 2 | import { ILoadOrderEntry, LoadOrder } from '../types/types'; 3 | 4 | // Change a specific load order entry. 5 | export const setFBLoadOrderEntry = 6 | createAction('SET_FB_LOAD_ORDER_ENTRY', 7 | (profileId: string, loEntry: ILoadOrderEntry) => 8 | ({ profileId, loEntry })) as any; 9 | 10 | export const setFBLoadOrder = 11 | createAction('SET_FB_LOAD_ORDER', 12 | (profileId: string, loadOrder: LoadOrder) => 13 | ({ profileId, loadOrder })) as any; 14 | -------------------------------------------------------------------------------- /src/extensions/firststeps_dashlet/IToDo.ts: -------------------------------------------------------------------------------- 1 | import { ToDoType } from '../../types/IExtensionContext'; 2 | 3 | import { TFunction } from 'i18next'; 4 | 5 | export interface IToDo { 6 | id: string; 7 | type: ToDoType; 8 | props?: (state: any) => any; 9 | icon: ((props: any) => JSX.Element) | string; 10 | text: ((t: TFunction, props: any) => JSX.Element | string) | string; 11 | value?: ((t: TFunction, props: any) => JSX.Element | string) | string; 12 | condition?: (props: any) => boolean; 13 | action?: (props: any) => void; 14 | priority?: number; 15 | } 16 | -------------------------------------------------------------------------------- /src/extensions/firststeps_dashlet/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | /** 4 | * dismiss a todo message from the "first steps" list 5 | */ 6 | export const dismissStep = safeCreateAction('DISMISS_STEP', step => step); 7 | -------------------------------------------------------------------------------- /src/extensions/firststeps_dashlet/reducers.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../types/IExtensionContext'; 2 | import {setSafe} from '../../util/storeHelper'; 3 | 4 | import * as actions from './actions'; 5 | 6 | /** 7 | * reducer for changes to interface settings 8 | */ 9 | const settingsReducer: IReducerSpec = { 10 | reducers: { 11 | [actions.dismissStep as any]: 12 | (state, payload) => setSafe(state, ['steps', payload], true), 13 | }, 14 | defaults: { 15 | dismissAll: false, 16 | steps: {}, 17 | }, 18 | }; 19 | 20 | export default settingsReducer; 21 | -------------------------------------------------------------------------------- /src/extensions/gamemode_management/actions/discovery.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | export const setPhaseCount = safeCreateAction('SET_DISCOVERY_PHASE_COUNT', count => count); 6 | 7 | export const discoveryProgress = safeCreateAction('DISCOVERY_PROGRESS', 8 | (idx: number, percent: number, directory: string) => ({ idx, percent, directory })); 9 | 10 | export const discoveryFinished = safeCreateAction('DISCOVERY_FINISHED'); 11 | -------------------------------------------------------------------------------- /src/extensions/gamemode_management/actions/persistent.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | export const setGameInfo = safeCreateAction('SET_GAME_INFO', 6 | (gameId: string, provider: string, priority: number, expires: number, 7 | values: Array<{ key: string, title: string, value: any }>) => 8 | ({ gameId, provider, priority, expires, values })); 9 | -------------------------------------------------------------------------------- /src/extensions/gamemode_management/actions/session.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | /** 6 | * sets the list of known/supported games 7 | */ 8 | export const setKnownGames = safeCreateAction('SET_KNOWN_GAMES', games => games); 9 | 10 | export const clearGameDisabled = safeCreateAction('CLEAR_GAME_DISABLED'); 11 | 12 | export const setGameDisabled = safeCreateAction('SET_GAME_DISABLED', 13 | (gameId: string, disabledBy: string) => ({ gameId, disabledBy })); 14 | -------------------------------------------------------------------------------- /src/extensions/gamemode_management/constants.ts: -------------------------------------------------------------------------------- 1 | export const SITE_ID = 'site'; 2 | -------------------------------------------------------------------------------- /src/extensions/gamemode_management/reducers/session.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | 3 | import * as actions from '../actions/session'; 4 | 5 | import update from 'immutability-helper'; 6 | import { setSafe } from '../../../util/storeHelper'; 7 | 8 | /** 9 | * reducer for changes to ephemeral session state 10 | */ 11 | export const sessionReducer: IReducerSpec = { 12 | reducers: { 13 | [actions.setKnownGames as any]: (state, payload) => update(state, { known: { $set: payload } }), 14 | [actions.setGameDisabled as any]: (state, payload) => 15 | setSafe(state, [ 'disabled', payload.gameId ], payload.disabledBy), 16 | [actions.clearGameDisabled as any]: (state, payload) => 17 | update(state, { disabled: { $set: {} } }), 18 | }, 19 | defaults: { 20 | known: [], 21 | disabled: {}, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/extensions/gamemode_management/types/IModType.ts: -------------------------------------------------------------------------------- 1 | import {IInstruction, IModTypeOptions} from '../../../types/IExtensionContext'; 2 | import {IGame} from '../../../types/IGame'; 3 | 4 | import Promise from 'bluebird'; 5 | 6 | export interface IModType { 7 | typeId: string; 8 | priority: number; 9 | isSupported: (gameId: string) => boolean; 10 | getPath: (game: IGame) => string; 11 | test: (installInstructions: IInstruction[]) => Promise; 12 | options: IModTypeOptions; 13 | } 14 | -------------------------------------------------------------------------------- /src/extensions/gamemode_management/types/IToolStored.ts: -------------------------------------------------------------------------------- 1 | export interface IToolStored { 2 | id: string; 3 | name: string; 4 | shortName?: string; 5 | logo: string; 6 | executable: string; 7 | parameters: string[]; 8 | environment: { [key: string]: string }; 9 | shell?: boolean; 10 | detach?: boolean; 11 | onStart?: 'hide' | 'hide_recover' | 'close'; 12 | exclusive?: boolean; 13 | defaultPrimary?: boolean; 14 | } 15 | -------------------------------------------------------------------------------- /src/extensions/gameversion_management/types/IGameVersionProvider.ts: -------------------------------------------------------------------------------- 1 | import { IGame } from '../../../types/IGame'; 2 | import { IDiscoveryResult } from '../../gamemode_management/types/IDiscoveryResult'; 3 | 4 | export type GameVersionProviderFunc = 5 | (game: IGame, discovery: IDiscoveryResult) => PromiseLike; 6 | export type GameVersionProviderTest = 7 | (game: IGame, discovery: IDiscoveryResult) => PromiseLike; 8 | 9 | export interface IGameVersionProviderOptions { } // One day this will make sense. 10 | export interface IGameVersionProvider { 11 | id: string; 12 | priority: number; 13 | supported: GameVersionProviderTest; 14 | getGameVersion: GameVersionProviderFunc; 15 | options?: IGameVersionProviderOptions; 16 | } 17 | -------------------------------------------------------------------------------- /src/extensions/history_management/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | import { IHistoryEvent } from './types'; 3 | 4 | export const addHistoryEvent = safeCreateAction('HISTORY_ADD_EVENT', 5 | (stack: string, event: IHistoryEvent, limit: number) => ({ stack, event, limit })); 6 | 7 | export const setHistoryEvent = safeCreateAction('HISTORY_SET_EVENT', 8 | (stack: string, event: IHistoryEvent) => ({ stack, event })); 9 | 10 | export const markHistoryReverted = safeCreateAction('HISTORY_MARK_REVERTED', 11 | (stack: string, event: IHistoryEvent) => ({ stack, event })); 12 | 13 | export const showHistory = safeCreateAction('HISTORY_SHOW', 14 | (stack: string) => stack); 15 | -------------------------------------------------------------------------------- /src/extensions/installer_fomod/actions/installerUI.ts: -------------------------------------------------------------------------------- 1 | import createAction from '../../../actions/safeCreateAction'; 2 | import { IInstallerInfo, IInstallerState } from '../types/interface'; 3 | 4 | import * as reduxAct from 'redux-act'; 5 | 6 | export const startDialog = createAction('START_FOMOD_DIALOG', (info: IInstallerInfo): any => info); 7 | 8 | export const endDialog = createAction('END_FOMOD_DIALOG'); 9 | 10 | export const clearDialog = createAction('CLEAR_FOMOD_DIALOG'); 11 | 12 | export const setDialogState = createAction('SET_FOMOD_DIALOG_STATE', 13 | (state: IInstallerState): any => state); 14 | 15 | export const setInstallerDataPath = createAction('SET_INSTALLER_DATA_PATH', 16 | (path: string): any => path); 17 | -------------------------------------------------------------------------------- /src/extensions/installer_fomod/actions/settings.ts: -------------------------------------------------------------------------------- 1 | import createAction from '../../../actions/safeCreateAction'; 2 | 3 | export const setInstallerSandbox = createAction('SET_INSTALLER_SANDBOX', (enabled: boolean) => enabled); 4 | 5 | -------------------------------------------------------------------------------- /src/extensions/installer_fomod/constants.ts: -------------------------------------------------------------------------------- 1 | export const CONTAINER_NAME: string = 'fomod-container'; 2 | 3 | export const NET_CORE_DOWNLOAD_SITE: string = 4 | 'https://dotnet.microsoft.com/en-us/download/dotnet/6.0/runtime'; 5 | 6 | export const NET_CORE_DOWNLOAD: string = 7 | 'https://download.visualstudio.microsoft.com/download/pr/3136e217-e5b7-4899-9b7e-aa52ecb8b108/d74134edaa75e3300f8692660b9fb7b5/windowsdesktop-runtime-6.0.26-win-x64.exe'; 8 | -------------------------------------------------------------------------------- /src/extensions/installer_fomod/delegates/Core.ts: -------------------------------------------------------------------------------- 1 | import {IExtensionApi} from '../../../types/IExtensionContext'; 2 | import Context from './Context'; 3 | import Ini from './Ini'; 4 | import Plugins from './Plugins'; 5 | import UI from './UI'; 6 | 7 | export class Core { 8 | public context: Context; 9 | public ini: Ini; 10 | public plugin: Plugins; 11 | public ui: UI; 12 | 13 | constructor(api: IExtensionApi, gameId: string, unattended: boolean) { 14 | this.plugin = new Plugins(api, gameId); 15 | this.ini = new Ini(api, gameId); 16 | this.ui = new UI(api, gameId, unattended); 17 | this.context = new Context(api, gameId); 18 | } 19 | 20 | public detach() { 21 | this.plugin.detach(); 22 | this.ini.detach(); 23 | this.ui.detach(); 24 | this.context.detach(); 25 | } 26 | } 27 | 28 | export default Core; 29 | -------------------------------------------------------------------------------- /src/extensions/installer_fomod/delegates/DelegateBase.ts: -------------------------------------------------------------------------------- 1 | import {IExtensionApi} from '../../../types/IExtensionContext'; 2 | 3 | class DelegateBase { 4 | private mApi; 5 | 6 | constructor(api: IExtensionApi) { 7 | this.mApi = api; 8 | } 9 | 10 | public detach(): void { 11 | // nop 12 | } 13 | 14 | get api(): IExtensionApi { 15 | return this.mApi; 16 | } 17 | } 18 | 19 | export default DelegateBase; 20 | -------------------------------------------------------------------------------- /src/extensions/installer_fomod/reducers/settings.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { setSafe } from '../../../util/storeHelper'; 3 | 4 | import * as actions from '../actions/settings'; 5 | 6 | export const settingsReducer: IReducerSpec = { 7 | reducers: { 8 | [actions.setInstallerSandbox as any]: 9 | (state, payload) => setSafe(state, ['installerSandbox'], payload), 10 | }, 11 | defaults: { 12 | installerSandbox: true, 13 | }, 14 | }; -------------------------------------------------------------------------------- /src/extensions/instructions_overlay/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | import { IOverlayOptions, IPosition } from '../../types/api'; 4 | 5 | export const showOverlay = safeCreateAction('SHOW_INSTRUCTIONS', 6 | (id: string, title: string, content: string | React.ComponentType, pos: IPosition, options: IOverlayOptions) => 7 | ({ id, title, content, pos, options })); 8 | 9 | export const dismissOverlay = safeCreateAction('DISMISS_INSTRUCTIONS', 10 | (id: string) => id); 11 | -------------------------------------------------------------------------------- /src/extensions/instructions_overlay/reducer.ts: -------------------------------------------------------------------------------- 1 | import { addReducer, IReducerSpec } from '../../types/IExtensionContext'; 2 | import { IOverlaysState } from '../../types/IState'; 3 | import { deleteOrNop, setSafe } from '../../util/storeHelper'; 4 | import * as actions from './actions'; 5 | 6 | const sessionReducer: IReducerSpec = { 7 | reducers: { 8 | ...addReducer(actions.showOverlay, (state, payload) => 9 | setSafe(state, ['overlays', payload.id], 10 | { title: payload.title, content: payload.content, position: payload.pos, options: payload.options })), 11 | ...addReducer(actions.dismissOverlay, (state, payload) => 12 | deleteOrNop(state, ['overlays', payload])), 13 | }, 14 | defaults: { 15 | overlays: {}, 16 | }, 17 | }; 18 | 19 | export default sessionReducer; 20 | -------------------------------------------------------------------------------- /src/extensions/mod_load_order/actions/loadOrder.ts: -------------------------------------------------------------------------------- 1 | import createAction from '../../../actions/safeCreateAction'; 2 | import { ILoadOrderEntry } from '../types/types'; 3 | 4 | // Change a specific load order entry. 5 | export const setLoadOrderEntry = 6 | createAction('SET_LOAD_ORDER_ENTRY', 7 | (profileId: string, modId: string, loEntry: ILoadOrderEntry) => 8 | ({ profileId, modId, loEntry })) as any; 9 | -------------------------------------------------------------------------------- /src/extensions/mod_load_order/actions/settings.ts: -------------------------------------------------------------------------------- 1 | import createAction from '../../../actions/safeCreateAction'; 2 | import { IItemRendererOptions } from '../types/types'; 3 | 4 | // Can be used to store game specific load order options 5 | // for the specified gameId. 6 | export const setGameLoadOrderRendererOptions = 7 | createAction('SET_LOAD_ORDER_RENDERER_OPTIONS', 8 | (gameId: string, itemRendererOptions: IItemRendererOptions) => 9 | ({ gameId, itemRendererOptions })) as any; 10 | -------------------------------------------------------------------------------- /src/extensions/mod_load_order/reducers/loadOrder.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { setSafe } from '../../../util/storeHelper'; 3 | 4 | import * as actions from '../actions/loadOrder'; 5 | 6 | export const modLoadOrderReducer: IReducerSpec = { 7 | reducers: { 8 | [actions.setLoadOrderEntry as any]: (state, payload) => { 9 | const { profileId, modId, loEntry } = payload; 10 | return setSafe(state, [profileId, modId], loEntry); 11 | }, 12 | }, 13 | defaults: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /src/extensions/mod_load_order/reducers/settings.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { setSafe } from '../../../util/storeHelper'; 3 | 4 | import * as actions from '../actions/settings'; 5 | 6 | export const loadOrderSettingsReducer: IReducerSpec = { 7 | reducers: { 8 | [actions.setGameLoadOrderRendererOptions as any]: (state, payload) => { 9 | const { gameId, itemRendererOptions } = payload; 10 | return setSafe(state, ['rendererOptions', gameId], itemRendererOptions); 11 | }, 12 | }, 13 | defaults: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /src/extensions/mod_load_order/views/DefaultInfoPanel.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { withTranslation } from 'react-i18next'; 3 | import { ComponentEx } from '../../../util/ComponentEx'; 4 | 5 | interface IProps { 6 | infoText: string; 7 | } 8 | 9 | class DefaultInfoPanel extends ComponentEx { 10 | constructor(props: IProps) { 11 | super(props); 12 | this.initState({}); 13 | } 14 | 15 | public render() { 16 | const { t, infoText } = this.props; 17 | return ( 18 |
19 |

{t('Changing your load order')}

20 |

{infoText}

21 |
22 | ); 23 | } 24 | 25 | } 26 | 27 | export default withTranslation(['common']) 28 | ((DefaultInfoPanel) as any) as React.ComponentClass<{infoText: string}>; 29 | -------------------------------------------------------------------------------- /src/extensions/mod_management/actions/deployment.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | export const setDeploymentNecessary = safeCreateAction('SET_NEED_DEPLOYMENT', 6 | (gameId: string, required: boolean) => ({ gameId, required })); 7 | -------------------------------------------------------------------------------- /src/extensions/mod_management/actions/transactions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | /** 4 | * Used to track transfer attempts and correctly recover if it gets interrupted. 5 | */ 6 | export const setTransferMods = safeCreateAction('SET_TRANSFER_MODS', 7 | (gameId: string, destination: string) => ({ gameId, destination })); 8 | -------------------------------------------------------------------------------- /src/extensions/mod_management/constants.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | export const VORTEX_OVERRIDE_INSTRUCTIONS_FILENAME = 'vortex_override_instructions.json'; 4 | 5 | export const DEPLOY_BLACKLIST: string[] = [ 6 | path.join('**', '.git', '**', '*'), 7 | path.join('**', '.gitignore'), 8 | path.join('**', '.hgignore'), 9 | path.join('**', '.gitattributes'), 10 | path.join('**', 'meta.ini'), 11 | path.join('**', '_macosx', '**', '*'), 12 | path.join('**', VORTEX_OVERRIDE_INSTRUCTIONS_FILENAME), 13 | ]; 14 | 15 | export const MIN_VARIANT_NAME = 1; 16 | export const MAX_VARIANT_NAME = 30; 17 | -------------------------------------------------------------------------------- /src/extensions/mod_management/reducers/deployment.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { setSafe } from '../../../util/storeHelper'; 3 | import * as actions from '../actions/deployment'; 4 | 5 | export const deploymentReducer: IReducerSpec = { 6 | reducers: { 7 | [actions.setDeploymentNecessary as any]: (state, payload) => 8 | setSafe(state, ['needToDeploy', payload.gameId], payload.required), 9 | }, 10 | defaults: { 11 | needToDeploy: {}, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/extensions/mod_management/reducers/transactions.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { deleteOrNop, setSafe } from '../../../util/storeHelper'; 3 | import * as actions from '../actions/transactions'; 4 | 5 | export const transactionsReducer: IReducerSpec = { 6 | reducers: { 7 | [actions.setTransferMods as any]: (state, payload) => { 8 | const { gameId, destination } = payload; 9 | return ((destination === undefined) || (destination === '')) 10 | ? deleteOrNop(state, ['transfer', gameId]) 11 | : setSafe(state, ['transfer', gameId], destination); 12 | }, 13 | }, 14 | defaults: { 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IDeployOptions.ts: -------------------------------------------------------------------------------- 1 | export interface IDeployOptions { 2 | manual?: boolean; 3 | profileId?: string; 4 | } -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IDeploymentManifest.ts: -------------------------------------------------------------------------------- 1 | import {IDeployedFile} from './IDeploymentMethod'; 2 | 3 | export interface IDeploymentManifest { 4 | version: number; 5 | instance: string; 6 | deploymentMethod?: string; 7 | deploymentTime?: number; 8 | stagingPath?: string; 9 | gameId?: string; 10 | targetPath?: string; 11 | files: IDeployedFile[]; 12 | } 13 | 14 | export type ManifestFormat = (input: any) => IDeploymentManifest; 15 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IFileEntry.ts: -------------------------------------------------------------------------------- 1 | export type FileActionRef = 'import' | 'drop' | 'newest'; 2 | export type FileActionVal = 'nop'; 3 | export type FileActionDel = 'restore' | 'delete'; 4 | export type FileActionSrcDel = 'drop' | 'import'; 5 | 6 | export type FileAction = FileActionRef | FileActionVal | FileActionDel | FileActionSrcDel; 7 | 8 | export interface IFileEntry { 9 | filePath: string; 10 | source: string; 11 | type: 'refchange' | 'valchange' | 'deleted' | 'srcdeleted'; 12 | action: FileAction; 13 | modTypeId: string; 14 | sourceModified: Date; 15 | destModified: Date; 16 | } 17 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IFileMerge.ts: -------------------------------------------------------------------------------- 1 | import {MergeFunc, MergeTest} from '../../../types/IExtensionContext'; 2 | 3 | export interface IFileMerge { 4 | test: MergeTest; 5 | merge: MergeFunc; 6 | modType: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IInstallContext.ts: -------------------------------------------------------------------------------- 1 | import { IMod } from './IMod'; 2 | 3 | export type InstallOutcome = 'success' | 'failed' | 'canceled' | 'ignore'; 4 | 5 | export interface IInstallContext { 6 | startIndicator: (id: string) => void; 7 | stopIndicator: (mod?: IMod) => void; 8 | setProgress: (phase: string, percent?: number) => void; 9 | startInstallCB: (id: string, gameId: string, archiveId: string) => 10 | void; 11 | finishInstallCB: (success: InstallOutcome, info?: any) => void; 12 | progressCB: (percent: number, file: string) => void; 13 | reportError: (message: string, details?: string | Error) => void; 14 | } 15 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IInstallOptions.ts: -------------------------------------------------------------------------------- 1 | import { IFileListItem } from './IMod'; 2 | 3 | export interface IInstallOptions { 4 | allowAutoEnable?: boolean; 5 | choices?: any; 6 | forceInstaller?: string; 7 | unattended?: boolean; 8 | fileList?: IFileListItem[]; 9 | patches?: any; 10 | variantNumber?: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IInstallResult.ts: -------------------------------------------------------------------------------- 1 | import { IRule } from './IMod'; 2 | 3 | export type InstructionType = 4 | 'copy' | 'mkdir' | 'submodule' | 'generatefile' | 'iniedit' 5 | | 'unsupported' | 'attribute' | 'setmodtype' | 'error' 6 | | 'rule'; 7 | 8 | export interface IInstruction { 9 | type: InstructionType; 10 | 11 | path?: string; 12 | source?: string; 13 | destination?: string; 14 | section?: string; 15 | key?: string; 16 | value?: any; 17 | submoduleType?: string; 18 | data?: string | Buffer; 19 | rule?: IRule; 20 | } 21 | 22 | export interface IInstallResult { 23 | instructions: IInstruction[]; 24 | } 25 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IModInstaller.ts: -------------------------------------------------------------------------------- 1 | import {InstallFunc} from './InstallFunc'; 2 | import {TestSupported} from './TestSupported'; 3 | 4 | export interface IModInstaller { 5 | id: string; 6 | priority: number; 7 | testSupported: TestSupported; 8 | install: InstallFunc; 9 | } 10 | 11 | export interface ISupportedInstaller { 12 | installer: IModInstaller; 13 | requiredFiles: string[]; 14 | } 15 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IModProps.ts: -------------------------------------------------------------------------------- 1 | import { IDownload } from '../../download_management/types/IDownload'; 2 | import { IProfileMod } from '../../profile_management/types/IProfile'; 3 | 4 | import { IMod } from './IMod'; 5 | 6 | export interface IModProps { 7 | mods: { [modId: string]: IMod }; 8 | modState: { [modId: string]: IProfileMod }; 9 | downloads: { [downloadId: string]: IDownload }; 10 | } 11 | 12 | export type IModWithState = IMod & IProfileMod; 13 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IModSource.ts: -------------------------------------------------------------------------------- 1 | import { IModSourceOptions } from '../../../types/IExtensionContext'; 2 | 3 | export interface IModSource { 4 | id: string; 5 | name: string; 6 | onBrowse?: () => void; 7 | options?: IModSourceOptions; 8 | } 9 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IResolvedMerger.ts: -------------------------------------------------------------------------------- 1 | import {IMergeFilter, MergeFunc} from '../../../types/IExtensionContext'; 2 | 3 | export interface IResolvedMerger { 4 | match: IMergeFilter; 5 | merge: MergeFunc; 6 | modType: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/IStateMods.ts: -------------------------------------------------------------------------------- 1 | import { IMod } from './IMod'; 2 | 3 | export interface IStateMods { 4 | mods: { [id: string]: IMod }; 5 | } 6 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/InstallFunc.ts: -------------------------------------------------------------------------------- 1 | import {IInstallResult} from './IInstallResult'; 2 | 3 | import Promise from 'bluebird'; 4 | 5 | export type ProgressDelegate = (perc: number) => void; 6 | 7 | export type InstallFunc = 8 | (files: string[], destinationPath: string, gameId: string, 9 | progressDelegate: ProgressDelegate, choices?: any, 10 | unattended?: boolean, archivePath?: string) => Promise; 11 | -------------------------------------------------------------------------------- /src/extensions/mod_management/types/TestSupported.ts: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | 3 | export interface ISupportedResult { 4 | supported: boolean; 5 | requiredFiles: string[]; 6 | } 7 | 8 | export type TestSupported = 9 | (files: string[], gameId: string, archivePath?: string) => Promise; 10 | -------------------------------------------------------------------------------- /src/extensions/mod_management/util/BlacklistSet.ts: -------------------------------------------------------------------------------- 1 | import minimatch from 'minimatch'; 2 | import { DEPLOY_BLACKLIST } from '../constants'; 3 | import { Normalize } from '../../../util/getNormalizeFunc'; 4 | import { IGame } from '../../../types/IGame'; 5 | 6 | export default class BlacklistSet extends Set { 7 | private mPatterns: string[]; 8 | constructor(blacklist: string[], game: IGame, normalize: Normalize) { 9 | super(blacklist.map(iter => normalize(iter))); 10 | this.mPatterns = [].concat(DEPLOY_BLACKLIST, game.details?.ignoreDeploy ?? []); 11 | } 12 | 13 | public has(value: string): boolean { 14 | return super.has(value) 15 | || (this.mPatterns.find(pat => minimatch(value, pat, { nocase: true })) !== undefined); 16 | } 17 | } -------------------------------------------------------------------------------- /src/extensions/mod_management/util/basicInstaller.ts: -------------------------------------------------------------------------------- 1 | import {ProgressDelegate} from '../types/InstallFunc'; 2 | import {ISupportedResult} from '../types/TestSupported'; 3 | 4 | import Promise from 'bluebird'; 5 | import * as path from 'path'; 6 | 7 | export function testSupported(files: string[]): Promise { 8 | const result: ISupportedResult = { supported: true, requiredFiles: [] }; 9 | return Promise.resolve(result); 10 | } 11 | 12 | export function install(files: string[], destinationPath: string, 13 | gameId: string, progress: ProgressDelegate): Promise { 14 | return Promise.resolve({ 15 | message: 'Success', 16 | instructions: files 17 | .filter((name: string) => !name.endsWith(path.sep)) 18 | .map((name: string) => ({ type: 'copy', source: name, destination: name })), 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /src/extensions/mod_management/util/exceptions.ts: -------------------------------------------------------------------------------- 1 | export class NoDeployment extends Error { 2 | constructor() { 3 | super('No supported deployment method'); 4 | this.name = this.constructor.name; 5 | this['allowReport'] = false; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/extensions/mod_management/util/manifest_formats/format_1.ts: -------------------------------------------------------------------------------- 1 | import { IDeploymentManifest } from '../../types/IDeploymentManifest'; 2 | 3 | function deserialize(input: any): IDeploymentManifest { 4 | return { 5 | version: 1, 6 | instance: input.instance, 7 | files: input.files, 8 | gameId: input.gameId, 9 | deploymentMethod: input.deploymentMethod, 10 | deploymentTime: input.deploymentTime, 11 | stagingPath: input.stagingPath, 12 | targetPath: input.targetPath, 13 | }; 14 | } 15 | 16 | export default deserialize; 17 | -------------------------------------------------------------------------------- /src/extensions/mod_management/util/modSource.ts: -------------------------------------------------------------------------------- 1 | import { IModSourceOptions } from '../../../types/IExtensionContext'; 2 | import {IModSource} from '../types/IModSource'; 3 | 4 | const modSources: IModSource[] = []; 5 | 6 | export function getModSources(): IModSource[] { 7 | return modSources; 8 | } 9 | 10 | export function getModSource(id: string): IModSource { 11 | return modSources.find(iter => iter.id === id); 12 | } 13 | 14 | export function registerModSource(id: string, 15 | name: string, 16 | onBrowse?: () => void, 17 | options?: IModSourceOptions) { 18 | modSources.push({ id, name, onBrowse, options }); 19 | } 20 | -------------------------------------------------------------------------------- /src/extensions/mod_management/util/versionClean.ts: -------------------------------------------------------------------------------- 1 | import * as semver from 'semver'; 2 | 3 | function versionClean(input: string): string { 4 | let res = semver.valid( 5 | semver.coerce(input, { includePrerelease: true }) 6 | ); 7 | if (res !== null) { 8 | res = semver.clean(res); 9 | } 10 | return res || '0.0.0-' + input; 11 | } 12 | 13 | export default versionClean; 14 | -------------------------------------------------------------------------------- /src/extensions/news_dashlet/constants.ts: -------------------------------------------------------------------------------- 1 | export const GAMEID_PLACEHOLDER = '__gameid__'; 2 | 3 | export const MAX_SUMMARY_LENGTH = 200; 4 | -------------------------------------------------------------------------------- /src/extensions/news_dashlet/types.ts: -------------------------------------------------------------------------------- 1 | export interface IExtra { 2 | id: string; 3 | value: any; 4 | icon?: string; 5 | text?: string; 6 | } 7 | 8 | export interface IModListItem { 9 | name: string; 10 | summary: string; 11 | category: string; 12 | author: string; 13 | imageUrl: string; 14 | link: string; 15 | extra: IExtra[]; 16 | } 17 | 18 | export interface IListItem { 19 | name: string | React.ReactChild[]; 20 | summary: string | React.ReactChild[]; 21 | category?: string; 22 | imageUrl: string; 23 | link: string; 24 | extra: IExtra[]; 25 | } 26 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/actions/account.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | /* 6 | * action to set the user API Key. Takes one parameter, the api key as a string 7 | */ 8 | export const setUserAPIKey = safeCreateAction('SET_USER_API_KEY', key => key); 9 | 10 | export const clearOAuthCredentials = safeCreateAction('CLEAR_OAUTH_CREDENTIALS', () => null); 11 | 12 | export const setOAuthCredentials = safeCreateAction('SET_OAUTH_CREDENTIALS', (token: string, refreshToken: string, fingerprint: string) => ({ 13 | token, refreshToken, fingerprint, 14 | })); 15 | 16 | /* 17 | * set to true if a logout was forced, normally via a migration 18 | */ 19 | export const setForcedLogout = safeCreateAction('SET_FORCED_LOGOUT', (value:boolean) => value); -------------------------------------------------------------------------------- /src/extensions/nexus_integration/actions/persistent.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | function id(input) { 4 | return input; 5 | } 6 | 7 | /** 8 | * action to set the user info nexus associates with an api key 9 | */ 10 | export const setUserInfo = safeCreateAction('SET_USER_INFO', id); 11 | 12 | 13 | /** 14 | * remember current version available on nexus 15 | */ 16 | export const setNewestVersion = safeCreateAction('SET_NEWEST_VERSION', id); 17 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/actions/settings.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | /* 6 | * associate with nxm urls 7 | */ 8 | export const setAssociatedWithNXMURLs = 9 | safeCreateAction('SET_ASSOCIATED_WITH_NXM_URLS', assoc => assoc); 10 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/reducers/settings.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../../types/IExtensionContext'; 2 | import { setSafe } from '../../../util/storeHelper'; 3 | 4 | import { setAssociatedWithNXMURLs } from '../actions/settings'; 5 | 6 | /** 7 | * reducer for changes to the authentication 8 | */ 9 | export const settingsReducer: IReducerSpec = { 10 | reducers: { 11 | [setAssociatedWithNXMURLs as any]: (state, payload) => 12 | setSafe(state, [ 'associateNXM' ], payload), 13 | }, 14 | defaults: { 15 | associateNXM: undefined, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/selectors.ts: -------------------------------------------------------------------------------- 1 | import { IState } from '../../types/IState'; 2 | import { getSafe } from '../../util/storeHelper'; 3 | 4 | import { createSelector } from 'reselect'; 5 | import { truthy } from '../../util/util'; 6 | 7 | export const apiKey = (state: IState) => 8 | getSafe(state, ['confidential', 'account', 'nexus', 'APIKey'], undefined); 9 | 10 | export const isLoggedIn = (state: IState) => { 11 | const APIKEY = state.confidential.account['nexus']?.APIKey; 12 | const OAuthCredentials = state.confidential.account['nexus']?.OAuthCredentials; 13 | return truthy(APIKEY) || truthy(OAuthCredentials); 14 | }; 15 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/types/IJWTAccessToken.ts: -------------------------------------------------------------------------------- 1 | export interface IJWTAccessToken { 2 | application_id: number; 3 | exp: number; 4 | fingerprint: string; 5 | iat: number; 6 | iss: string; 7 | jti: string; 8 | sub: number; 9 | user: { 10 | group_id: number; 11 | id: number; 12 | membership_roles: string[]; 13 | permissions: { [key: string]: string[] }; 14 | premium_expiry: number; 15 | username: string; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/types/IValidateKeyData.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Data retrieved with a correct API Key 3 | * 4 | * @export 5 | * @interface IValidateKeyData 6 | */ 7 | export interface IValidateKeyData { 8 | email: string; 9 | isPremium: boolean; 10 | isSupporter: boolean; 11 | name: string; 12 | profileUrl: string; 13 | userId: number; 14 | } 15 | 16 | export enum IAccountStatus { 17 | Premium, 18 | Supporter, 19 | Free, 20 | Banned, 21 | Closed 22 | } 23 | 24 | export interface IValidateKeyDataV2 extends IValidateKeyData { 25 | isLifetime?: boolean, 26 | isBanned?: boolean, 27 | isClosed?: boolean, 28 | status?: IAccountStatus 29 | } -------------------------------------------------------------------------------- /src/extensions/nexus_integration/util/UIDs.ts: -------------------------------------------------------------------------------- 1 | import { IModRepoId } from '../../mod_management/types/IMod'; 2 | import { nexusGames } from '../util'; 3 | 4 | const gameNum = (() => { 5 | let cache: { [gameId: string]: number }; 6 | return (gameId: string): number => { 7 | if (cache === undefined) { 8 | cache = nexusGames().reduce((prev, game) => { 9 | prev[game.domain_name] = game.id; 10 | return prev; 11 | }, {}); 12 | } 13 | 14 | return cache[gameId]; 15 | }; 16 | })(); 17 | 18 | export function makeFileUID(repoInfo: IModRepoId): string { 19 | return ((BigInt(gameNum(repoInfo.gameId)) << BigInt(32)) 20 | | BigInt(parseInt(repoInfo.fileId, 10))).toString(); 21 | } 22 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/util/sso.ts: -------------------------------------------------------------------------------- 1 | import { NEXUS_BASE_URL } from '../constants'; 2 | 3 | export function getPageURL(loginId: string) { 4 | return `${NEXUS_BASE_URL}/sso?application=vortex&id=${loginId}`; 5 | } 6 | -------------------------------------------------------------------------------- /src/extensions/nexus_integration/util/transformUserInfo.ts: -------------------------------------------------------------------------------- 1 | import {IValidateKeyData} from '../types/IValidateKeyData'; 2 | 3 | import {IValidateKeyResponse} from '@nexusmods/nexus-api'; 4 | 5 | // transform the server response into the format we store internally 6 | function transformUserInfo(input: IValidateKeyResponse): IValidateKeyData { 7 | return ({ 8 | email: input.email, 9 | isPremium: input.is_premium, 10 | isSupporter: input.is_supporter, 11 | name: input.name, 12 | profileUrl: input.profile_url, 13 | userId: input.user_id, 14 | }); 15 | } 16 | 17 | export default transformUserInfo; 18 | -------------------------------------------------------------------------------- /src/extensions/onboarding_dashlet/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | /** 4 | * completes a step 5 | */ 6 | export const completeStep = safeCreateAction('COMPLETE_STEP', step => step); 7 | export const resetSteps = safeCreateAction('RESET_STEPS'); 8 | -------------------------------------------------------------------------------- /src/extensions/onboarding_dashlet/reducers.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../types/IExtensionContext'; 2 | import {setSafe} from '../../util/storeHelper'; 3 | 4 | import * as actions from './actions'; 5 | 6 | /** 7 | * reducer for changes to interface settings 8 | */ 9 | const settingsReducer: IReducerSpec = { 10 | reducers: { 11 | [actions.completeStep as any]: (state, payload) => setSafe(state, ['steps', payload], true), 12 | [actions.resetSteps as any]: (state) => setSafe(state, ['steps'], {}), 13 | }, 14 | defaults: { 15 | steps: {}, 16 | }, 17 | }; 18 | 19 | export default settingsReducer; 20 | -------------------------------------------------------------------------------- /src/extensions/profile_management/actions/transferSetup.ts: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-act'; 2 | 3 | import { IProfile } from '../types/IProfile'; 4 | 5 | export const setSource = createAction('SET_PROFILE_CONNECTION_SOURCE', 6 | (id: string, pos: { x: number, y: number }) => ({ id, pos })); 7 | 8 | export const setTarget = createAction('SET_PROFILE_CONNECTION_TARGET', 9 | (id: string, pos: { x: number, y: number }) => ({ id, pos })); 10 | 11 | export const setCreateTransfer = createAction('SET_PROFILE_TRANSFER', 12 | (gameId: string, source: string, target: string) => 13 | ({ gameId, source, target })); 14 | 15 | export const closeDialog = createAction('CLOSE_PROFILE_TRANSFER_DIALOG'); 16 | -------------------------------------------------------------------------------- /src/extensions/profile_management/constants.ts: -------------------------------------------------------------------------------- 1 | export const STUCK_TIMEOUT: number = 30000; 2 | -------------------------------------------------------------------------------- /src/extensions/profile_management/texts.ts: -------------------------------------------------------------------------------- 1 | import { TFunction } from 'i18next'; 2 | 3 | function getText(id: string, t: TFunction) { 4 | switch (id) { 5 | case 'profiles': 6 | return t( 7 | 'Profiles allow you to have multiple mod set-ups for a game at once and quickly ' + 8 | 'switch between them. This can be useful when you have multiple playthroughs in ' + 9 | 'parallel or if multiple people play the same game on your computer.\n\n' + 10 | 'All profiles for a game share the set of "available" mods, but each has its own ' + 11 | 'list of "enabled" mods.\n\n' + 12 | 'Depending on the game, profiles can also have different plugins enabled, separate ' + 13 | 'save games, separate game configuration and so on.'); 14 | default: 15 | return undefined; 16 | } 17 | } 18 | 19 | export default getText; 20 | -------------------------------------------------------------------------------- /src/extensions/profile_management/types/Errors.ts: -------------------------------------------------------------------------------- 1 | import { IProfile } from './IProfile'; 2 | 3 | export class CorruptActiveProfile extends Error { 4 | constructor(profile: IProfile) { 5 | super('The active profile is corrupted, please create a new one.\n' 6 | + `Profile: ${JSON.stringify(profile)}`); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/extensions/profile_management/types/IProfile.ts: -------------------------------------------------------------------------------- 1 | export interface IProfileMod { 2 | enabled: boolean; 3 | enabledTime: number; 4 | } 5 | 6 | export interface IProfile { 7 | id: string; 8 | gameId: string; 9 | name: string; 10 | modState: { [id: string]: IProfileMod }; 11 | lastActivated: number; 12 | pendingRemove?: boolean; 13 | features?: { [featureId: string]: any }; 14 | } 15 | -------------------------------------------------------------------------------- /src/extensions/profile_management/types/IProfileFeature.ts: -------------------------------------------------------------------------------- 1 | export interface IProfileFeature { 2 | id: string; 3 | icon: string; 4 | label: string; 5 | // the type of the value. 6 | // This can be anything but only supported types will provide generic means to edit 7 | // and custom rendering 8 | // as of Vortex 1.4, only 'boolean' and 'text' have such handling, everything else will 9 | // be displayed with value.toString() and not editable (unless your extension provides something) 10 | type: string; 11 | description: string; 12 | supported: () => boolean; 13 | namespace?: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/extensions/settings_application/index.ts: -------------------------------------------------------------------------------- 1 | import { IExtensionContext } from '../../types/IExtensionContext'; 2 | import LazyComponent from '../../util/LazyComponent'; 3 | import {} from './SettingsVortex'; 4 | 5 | function init(context: IExtensionContext): boolean { 6 | context.registerSettings('Vortex', 7 | LazyComponent(() => require('./SettingsVortex')), 8 | undefined, 9 | undefined, 10 | 50); 11 | 12 | return true; 13 | } 14 | 15 | export default init; 16 | -------------------------------------------------------------------------------- /src/extensions/settings_interface/actions/automation.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | export const setAutoDeployment = safeCreateAction('SET_AUTO_DEPLOYMENT', deploy => deploy); 6 | export const setAutoInstall = safeCreateAction('SET_AUTO_INSTALL', enabled => enabled); 7 | export const setAutoEnable = safeCreateAction('SET_AUTO_ENABLE', enabled => enabled); 8 | export const setAutoStart = safeCreateAction('SET_AUTO_START', start => start); 9 | export const setStartMinimized = safeCreateAction('SET_START_MINIMIZED', minimized => minimized); 10 | -------------------------------------------------------------------------------- /src/extensions/settings_metaserver/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | /** 4 | * add a metaserver 5 | */ 6 | export const addMetaserver = safeCreateAction('ADD_METASERVER', 7 | (id: string, url: string) => ({ id, url })); 8 | 9 | /** 10 | * remove a metaserver 11 | */ 12 | export const removeMetaserver = safeCreateAction('REMOVE_METASERVER', 13 | (id: string, cacheDurationSec?: number) => ({ id, cacheDurationSec })); 14 | 15 | /** 16 | * change the priority of a metaserver 17 | */ 18 | export const setPriorities = safeCreateAction('SET_METASERVER_PRIORITY', 19 | (ids: string[]) => ({ ids })); 20 | -------------------------------------------------------------------------------- /src/extensions/settings_metaserver/index.ts: -------------------------------------------------------------------------------- 1 | import { IExtensionContext } from '../../types/IExtensionContext'; 2 | import LazyComponent from '../../util/LazyComponent'; 3 | import settingsReducer from './reducers'; 4 | import {} from './SettingsMetaserver'; 5 | 6 | function init(context: IExtensionContext): boolean { 7 | context.registerReducer(['settings', 'metaserver'], settingsReducer); 8 | context.registerSettings('Download', LazyComponent(() => require('./SettingsMetaserver'))); 9 | 10 | return true; 11 | } 12 | 13 | export default init; 14 | -------------------------------------------------------------------------------- /src/extensions/settings_metaserver/texts.ts: -------------------------------------------------------------------------------- 1 | import { TFunction } from '../../util/i18n'; 2 | 3 | function getText(id: string, t: TFunction) { 4 | switch (id) { 5 | case 'meta-server': return t( 6 | 'A meta server provides additional information about mods, giving you ' 7 | + 'more details and dependency information about them. By default you ' 8 | + 'get this data from nexusmods.com but it\'s possible for others to set ' 9 | + 'up their own servers and then you can add those here to use them.'); 10 | default: return undefined; 11 | } 12 | } 13 | 14 | export default getText; 15 | -------------------------------------------------------------------------------- /src/extensions/starter_dashlet/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | export const setPrimaryTool = safeCreateAction('SET_PRIMARY_TOOL', 4 | (gameId: string, toolId: string) => ({ gameId, toolId })); 5 | 6 | export const setToolOrder = safeCreateAction('SET_TOOLS_ORDER', 7 | (gameId: string, tools: string[]) => ({ gameId, tools })); 8 | 9 | export const setToolValid = safeCreateAction('SET_TOOL_IS_VALID', 10 | (gameId: string, toolId: string, valid: boolean) => ({ gameId, toolId, valid })); 11 | -------------------------------------------------------------------------------- /src/extensions/starter_dashlet/reducers.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../types/IExtensionContext'; 2 | import { setSafe } from '../../util/storeHelper'; 3 | import * as actions from './actions'; 4 | 5 | const reducer: IReducerSpec = { 6 | reducers: { 7 | [actions.setPrimaryTool as any]: (state, payload) => 8 | setSafe(state, ['primaryTool', payload.gameId], payload.toolId), 9 | [actions.setToolOrder as any]: (state, payload) => { 10 | const { gameId, tools } = payload; 11 | return setSafe(state, ['tools', 'order', gameId], tools); 12 | }, 13 | [actions.setToolValid as any]: (state, payload) => { 14 | const { gameId, toolId, valid } = payload; 15 | return setSafe(state, ['tools', 'valid', gameId, toolId], valid); 16 | }, 17 | }, 18 | defaults: {}, 19 | }; 20 | 21 | export default reducer; 22 | -------------------------------------------------------------------------------- /src/extensions/starter_dashlet/types.ts: -------------------------------------------------------------------------------- 1 | export interface IReducerAction { 2 | type: keyof T; 3 | value: any; 4 | } 5 | export type StateReducerType = React.Reducer[]>; 6 | 7 | export interface IEditStarterInfo { 8 | id: string; 9 | gameId: string; 10 | isGame: boolean; 11 | iconPath: string; 12 | iconOutPath: string; 13 | name: string; 14 | exePath: string; 15 | commandLine: string; 16 | workingDirectory: string; 17 | environment: { [key: string]: string }; 18 | shell: boolean; 19 | detach: boolean; 20 | onStart?: 'hide' | 'hide_recover' | 'close'; 21 | defaultPrimary?: boolean; 22 | exclusive?: boolean; 23 | } 24 | -------------------------------------------------------------------------------- /src/extensions/starter_dashlet/useDebouncedCallback.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useCallback, DependencyList } from 'react'; 2 | 3 | export function useDebouncedCallback(callback: (...args: T) => void, 4 | wait: number, 5 | deps: DependencyList) { 6 | const argsRef = useRef(); 7 | const timeout = useRef>(); 8 | function cleanup() { 9 | if(timeout.current) { 10 | clearTimeout(timeout.current); 11 | } 12 | } 13 | useEffect(() => cleanup, []); 14 | return useCallback((...args: T) => { 15 | argsRef.current = args; 16 | cleanup(); 17 | timeout.current = setTimeout(() => { 18 | if(argsRef.current) { 19 | callback(...argsRef.current); 20 | } 21 | }, wait); 22 | }, deps); 23 | } -------------------------------------------------------------------------------- /src/extensions/symlink_activator_elevate/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | export const enableUserSymlinks = safeCreateAction('ENABLE_USER_SYMLINKS', 6 | (enabled: boolean) => enabled); 7 | -------------------------------------------------------------------------------- /src/extensions/symlink_activator_elevate/reducers.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../types/IExtensionContext'; 2 | 3 | import * as actions from './actions'; 4 | 5 | import update from 'immutability-helper'; 6 | 7 | /** 8 | * reducer for changes to interface settings 9 | */ 10 | const settingsReducer: IReducerSpec = { 11 | reducers: { 12 | [actions.enableUserSymlinks as any]: (state, payload) => 13 | update(state, { userSymlinks: { $set: payload } }), 14 | }, 15 | defaults: { 16 | userSymlinks: false, 17 | }, 18 | }; 19 | 20 | export default settingsReducer; 21 | -------------------------------------------------------------------------------- /src/extensions/updater/actions.ts: -------------------------------------------------------------------------------- 1 | import safeCreateAction from '../../actions/safeCreateAction'; 2 | 3 | import * as reduxAct from 'redux-act'; 4 | 5 | /** 6 | * changes the 'channel' from which to receive Vortex updates 7 | * currently either 'beta', 'stable' or 'none' 8 | */ 9 | export const setUpdateChannel = safeCreateAction('SET_UPDATE_CHANNEL', channel => channel); 10 | -------------------------------------------------------------------------------- /src/extensions/updater/reducers.ts: -------------------------------------------------------------------------------- 1 | import { IReducerSpec } from '../../types/IExtensionContext'; 2 | 3 | import { setUpdateChannel } from './actions'; 4 | 5 | import update from 'immutability-helper'; 6 | 7 | /** 8 | * reducer for changes to interface settings 9 | */ 10 | const settingsReducer: IReducerSpec = { 11 | reducers: { 12 | [setUpdateChannel as any]: (state, payload) => update(state, { channel: { $set: payload } }), 13 | }, 14 | defaults: { 15 | channel: 'stable', 16 | }, 17 | }; 18 | 19 | export default settingsReducer; 20 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vortex 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // top-level file for the 'api' which exposes components 2 | // that should be available to extensions 3 | 4 | import * as actions from './actions/index'; 5 | import * as types from './types/api'; 6 | import * as util from './util/api'; 7 | import * as fs from './util/fs'; 8 | import { log } from './util/log'; 9 | import * as selectors from './util/selectors'; 10 | 11 | import Promise from 'bluebird'; 12 | 13 | export * from './controls/api'; 14 | export * from './views/api'; 15 | export { actions, Promise, fs, log, selectors, types, util }; 16 | export { ComponentEx, PureComponentEx } from './util/ComponentEx'; 17 | -------------------------------------------------------------------------------- /src/reducers/loadOrder.ts: -------------------------------------------------------------------------------- 1 | import * as actions from '../actions/loadOrder'; 2 | import {IReducerSpec} from '../types/IExtensionContext'; 3 | import {setSafe} from '../util/storeHelper'; 4 | 5 | export const loReducer: IReducerSpec = { 6 | reducers: { 7 | [actions.setLoadOrder as any]: (state, payload) => setSafe(state, [payload.id], payload.order), 8 | }, 9 | defaults: { 10 | }, 11 | verifiers: { 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /src/reducers/notificationSettings.ts: -------------------------------------------------------------------------------- 1 | import * as actions from '../actions/notificationSettings'; 2 | import {IReducerSpec} from '../types/IExtensionContext'; 3 | import {setSafe} from '../util/storeHelper'; 4 | 5 | export const notificationSettingsReducer: IReducerSpec = { 6 | reducers: { 7 | [actions.suppressNotification as any]: (state, payload) => 8 | setSafe(state, ['suppress', payload.id], payload.suppress), 9 | [actions.resetSuppression as any]: (state) => 10 | setSafe(state, ['suppress'], {}), 11 | }, 12 | defaults: { 13 | suppress: {}, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/reducers/user.ts: -------------------------------------------------------------------------------- 1 | import * as actions from '../actions/user'; 2 | import {IReducerSpec} from '../types/IExtensionContext'; 3 | import {setSafe} from '../util/storeHelper'; 4 | 5 | export const userReducer: IReducerSpec = { 6 | reducers: { 7 | [actions.setMultiUser as any]: (state, payload) => setSafe(state, ['multiUser'], payload), 8 | }, 9 | defaults: { 10 | multiUser: false, 11 | }, 12 | verifiers: { 13 | multiUser: { 14 | description: () => 15 | 'Choice of "shared"/"per-user" mode was not stored, defaulting to "per-user" mode.', 16 | type: 'boolean', 17 | }, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/splash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vortex 7 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/splash.ts: -------------------------------------------------------------------------------- 1 | import {ipcRenderer} from 'electron'; 2 | 3 | ipcRenderer.on('fade-out', () => { 4 | const splash = document.getElementById('splash'); 5 | if (!!splash) { 6 | splash.setAttribute('transition', 'opacity 500ms ease-in-out'); 7 | splash.setAttribute('style', 'opacity: 0'); 8 | } 9 | }); 10 | 11 | const url = new URL(window.location.href); 12 | if (url.searchParams.get('disableGPU') === '1') { 13 | document.getElementById('bg').style.backgroundColor = '#d78f46'; 14 | } 15 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/_bootstrap-compass.scss: -------------------------------------------------------------------------------- 1 | @function twbs-font-path($path) { 2 | @return font-url($path, true); 3 | } 4 | 5 | @function twbs-image-path($path) { 6 | @return image-url($path, true); 7 | } 8 | 9 | $bootstrap-sass-asset-helper: true; 10 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/_bootstrap-mincer.scss: -------------------------------------------------------------------------------- 1 | // Mincer asset helper functions 2 | // 3 | // This must be imported into a .css.ejs.scss file. 4 | // Then, <% %>-interpolations will be parsed as strings by Sass, and evaluated by EJS after Sass compilation. 5 | 6 | 7 | @function twbs-font-path($path) { 8 | // do something like following 9 | // from "path/to/font.ext#suffix" to "<%- asset_path(path/to/font.ext)) + #suffix %>" 10 | // from "path/to/font.ext?#suffix" to "<%- asset_path(path/to/font.ext)) + ?#suffix %>" 11 | // or from "path/to/font.ext" just "<%- asset_path(path/to/font.ext)) %>" 12 | @return "<%- asset_path("#{$path}".replace(/[#?].*$/, '')) + "#{$path}".replace(/(^[^#?]*)([#?]?.*$)/, '$2') %>"; 13 | } 14 | 15 | @function twbs-image-path($file) { 16 | @return "<%- asset_path("#{$file}") %>"; 17 | } 18 | 19 | $bootstrap-sass-asset-helper: true; 20 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/_bootstrap-sprockets.scss: -------------------------------------------------------------------------------- 1 | @function twbs-font-path($path) { 2 | @return font-path($path); 3 | } 4 | 5 | @function twbs-image-path($path) { 6 | @return image-path($path); 7 | } 8 | 9 | $bootstrap-sass-asset-helper: true; 10 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/_breadcrumbs.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: $breadcrumb-padding-vertical $breadcrumb-padding-horizontal; 8 | margin-bottom: $line-height-computed; 9 | list-style: none; 10 | background-color: $breadcrumb-bg; 11 | border-radius: $border-radius-base; 12 | 13 | > li { 14 | display: inline-block; 15 | 16 | + li:before { 17 | // [converter] Workaround for https://github.com/sass/libsass/issues/1115 18 | $nbsp: "\00a0"; 19 | content: "#{$breadcrumb-separator}#{$nbsp}"; // Unicode space added since inline-block means non-collapsing white-space 20 | padding: 0 5px; 21 | color: $breadcrumb-color; 22 | } 23 | } 24 | 25 | > .active { 26 | color: $breadcrumb-active-color; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/_responsive-embed.scss: -------------------------------------------------------------------------------- 1 | // Embeds responsive 2 | // 3 | // Credit: Nicolas Gallagher and SUIT CSS. 4 | 5 | .embed-responsive { 6 | position: relative; 7 | display: block; 8 | height: 0; 9 | padding: 0; 10 | overflow: hidden; 11 | 12 | .embed-responsive-item, 13 | iframe, 14 | embed, 15 | object, 16 | video { 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | bottom: 0; 21 | height: 100%; 22 | width: 100%; 23 | border: 0; 24 | } 25 | } 26 | 27 | // Modifier class for 16:9 aspect ratio 28 | .embed-responsive-16by9 { 29 | padding-bottom: 56.25%; 30 | } 31 | 32 | // Modifier class for 4:3 aspect ratio 33 | .embed-responsive-4by3 { 34 | padding-bottom: 75%; 35 | } 36 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/_wells.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: $well-bg; 12 | border: 1px solid $well-border; 13 | border-radius: $border-radius-base; 14 | @include box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-lg { 23 | padding: 24px; 24 | border-radius: $border-radius-large; 25 | } 26 | .well-sm { 27 | padding: 9px; 28 | border-radius: $border-radius-small; 29 | } 30 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_alerts.scss: -------------------------------------------------------------------------------- 1 | // Alerts 2 | 3 | @mixin alert-variant($background, $border, $text-color) { 4 | background-color: $background; 5 | border-color: $border; 6 | color: $text-color; 7 | 8 | .btn-embed.no-hover { 9 | color: $text-color; 10 | } 11 | 12 | hr { 13 | border-top-color: darken($border, 5%); 14 | } 15 | .alert-link { 16 | color: darken($text-color, 10%); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_background-variant.scss: -------------------------------------------------------------------------------- 1 | // Contextual backgrounds 2 | 3 | // [converter] $parent hack 4 | @mixin bg-variant($parent, $color) { 5 | #{$parent} { 6 | background-color: $color; 7 | } 8 | a#{$parent}:hover, 9 | a#{$parent}:focus { 10 | background-color: darken($color, 10%); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_border-radius.scss: -------------------------------------------------------------------------------- 1 | // Single side border-radius 2 | 3 | @mixin border-top-radius($radius) { 4 | border-top-right-radius: $radius; 5 | border-top-left-radius: $radius; 6 | } 7 | @mixin border-right-radius($radius) { 8 | border-bottom-right-radius: $radius; 9 | border-top-right-radius: $radius; 10 | } 11 | @mixin border-bottom-radius($radius) { 12 | border-bottom-right-radius: $radius; 13 | border-bottom-left-radius: $radius; 14 | } 15 | @mixin border-left-radius($radius) { 16 | border-bottom-left-radius: $radius; 17 | border-top-left-radius: $radius; 18 | } 19 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_center-block.scss: -------------------------------------------------------------------------------- 1 | // Center-align a block level element 2 | 3 | @mixin center-block() { 4 | display: block; 5 | margin-left: auto; 6 | margin-right: auto; 7 | } 8 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_clearfix.scss: -------------------------------------------------------------------------------- 1 | // Clearfix 2 | // 3 | // For modern browsers 4 | // 1. The space content is one way to avoid an Opera bug when the 5 | // contenteditable attribute is included anywhere else in the document. 6 | // Otherwise it causes space to appear at the top and bottom of elements 7 | // that are clearfixed. 8 | // 2. The use of `table` rather than `block` is only necessary if using 9 | // `:before` to contain the top-margins of child elements. 10 | // 11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 12 | 13 | @mixin clearfix() { 14 | &:before, 15 | &:after { 16 | content: " "; // 1 17 | display: table; // 2 18 | } 19 | &:after { 20 | clear: both; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_hide-text.scss: -------------------------------------------------------------------------------- 1 | // CSS image replacement 2 | // 3 | // Heads up! v3 launched with only `.hide-text()`, but per our pattern for 4 | // mixins being reused as classes with the same name, this doesn't hold up. As 5 | // of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. 6 | // 7 | // Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 8 | 9 | // Deprecated as of v3.0.1 (has been removed in v4) 10 | @mixin hide-text() { 11 | font: 0/0 a; 12 | color: transparent; 13 | text-shadow: none; 14 | background-color: transparent; 15 | border: 0; 16 | } 17 | 18 | // New mixin to use as of v3.0.1 19 | @mixin text-hide() { 20 | @include hide-text; 21 | } 22 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_labels.scss: -------------------------------------------------------------------------------- 1 | // Labels 2 | 3 | @mixin label-variant($color) { 4 | background-color: $color; 5 | 6 | &[href] { 7 | &:hover, 8 | &:focus { 9 | background-color: darken($color, 10%); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_list-group.scss: -------------------------------------------------------------------------------- 1 | // List Groups 2 | 3 | @mixin list-group-item-variant($state, $background, $color) { 4 | .list-group-item-#{$state} { 5 | color: $color; 6 | background-color: $background; 7 | 8 | // [converter] extracted a&, button& to a.list-group-item-#{$state}, button.list-group-item-#{$state} 9 | } 10 | 11 | a.list-group-item-#{$state}, 12 | button.list-group-item-#{$state} { 13 | color: $color; 14 | 15 | .list-group-item-heading { 16 | color: inherit; 17 | } 18 | 19 | &:hover, 20 | &:focus { 21 | color: $color; 22 | background-color: darken($background, 5%); 23 | } 24 | &.active, 25 | &.active:hover, 26 | &.active:focus { 27 | color: #fff; 28 | background-color: $color; 29 | border-color: $color; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_nav-divider.scss: -------------------------------------------------------------------------------- 1 | // Horizontal dividers 2 | // 3 | // Dividers (basically an hr) within dropdowns and nav lists 4 | 5 | @mixin nav-divider($color: #e5e5e5) { 6 | height: 1px; 7 | margin: (($line-height-computed / 2) - 1) 0; 8 | overflow: hidden; 9 | background-color: $color; 10 | } 11 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_nav-vertical-align.scss: -------------------------------------------------------------------------------- 1 | // Navbar vertical align 2 | // 3 | // Vertically center elements in the navbar. 4 | // Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. 5 | 6 | @mixin navbar-vertical-align($element-height) { 7 | margin-top: (($navbar-height - $element-height) / 2); 8 | margin-bottom: (($navbar-height - $element-height) / 2); 9 | } 10 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_opacity.scss: -------------------------------------------------------------------------------- 1 | // Opacity 2 | 3 | @mixin opacity($opacity) { 4 | opacity: $opacity; 5 | // IE8 filter 6 | $opacity-ie: ($opacity * 100); 7 | filter: alpha(opacity=$opacity-ie); 8 | } 9 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_pagination.scss: -------------------------------------------------------------------------------- 1 | // Pagination 2 | 3 | @mixin pagination-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) { 4 | > li { 5 | > a, 6 | > span { 7 | padding: $padding-vertical $padding-horizontal; 8 | font-size: $font-size; 9 | line-height: $line-height; 10 | } 11 | &:first-child { 12 | > a, 13 | > span { 14 | @include border-left-radius($border-radius); 15 | } 16 | } 17 | &:last-child { 18 | > a, 19 | > span { 20 | @include border-right-radius($border-radius); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_panels.scss: -------------------------------------------------------------------------------- 1 | // Panels 2 | 3 | @mixin panel-variant($border, $heading-text-color, $heading-bg-color, $heading-border) { 4 | border-color: $border; 5 | 6 | & > .panel-heading { 7 | color: $heading-text-color; 8 | background-color: $heading-bg-color; 9 | border-color: $heading-border; 10 | 11 | + .panel-collapse > .panel-body { 12 | border-top-color: $border; 13 | } 14 | .badge { 15 | color: $heading-bg-color; 16 | background-color: $heading-text-color; 17 | } 18 | } 19 | & > .panel-footer { 20 | + .panel-collapse > .panel-body { 21 | border-bottom-color: $border; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_progress-bar.scss: -------------------------------------------------------------------------------- 1 | // Progress bars 2 | 3 | @mixin progress-bar-variant($color) { 4 | background-color: $color; 5 | 6 | // Deprecated parent class requirement as of v3.2.0 7 | .progress-striped & { 8 | @include gradient-striped; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_reset-filter.scss: -------------------------------------------------------------------------------- 1 | // Reset filters for IE 2 | // 3 | // When you need to remove a gradient background, do not forget to use this to reset 4 | // the IE filter for IE9 and below. 5 | 6 | @mixin reset-filter() { 7 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 8 | } 9 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_reset-text.scss: -------------------------------------------------------------------------------- 1 | @mixin reset-text() { 2 | font-family: $font-family-base; 3 | // We deliberately do NOT reset font-size. 4 | font-style: normal; 5 | font-weight: normal; 6 | letter-spacing: normal; 7 | line-break: auto; 8 | line-height: $line-height-base; 9 | text-align: left; // Fallback for where `start` is not supported 10 | text-align: start; 11 | text-decoration: none; 12 | text-shadow: none; 13 | text-transform: none; 14 | white-space: normal; 15 | word-break: normal; 16 | word-spacing: normal; 17 | word-wrap: normal; 18 | } 19 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_resize.scss: -------------------------------------------------------------------------------- 1 | // Resize anything 2 | 3 | @mixin resizable($direction) { 4 | resize: $direction; // Options: horizontal, vertical, both 5 | overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` 6 | } 7 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_responsive-visibility.scss: -------------------------------------------------------------------------------- 1 | // Responsive utilities 2 | 3 | // 4 | // More easily include all the states for responsive-utilities.less. 5 | // [converter] $parent hack 6 | @mixin responsive-visibility($parent) { 7 | #{$parent} { 8 | display: block !important; 9 | } 10 | table#{$parent} { display: table !important; } 11 | tr#{$parent} { display: table-row !important; } 12 | th#{$parent}, 13 | td#{$parent} { display: table-cell !important; } 14 | } 15 | 16 | // [converter] $parent hack 17 | @mixin responsive-invisibility($parent) { 18 | #{$parent} { 19 | display: none !important; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_size.scss: -------------------------------------------------------------------------------- 1 | // Sizing shortcuts 2 | 3 | @mixin size($width, $height) { 4 | width: $width; 5 | height: $height; 6 | } 7 | 8 | @mixin square($size) { 9 | @include size($size, $size); 10 | } 11 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_tab-focus.scss: -------------------------------------------------------------------------------- 1 | // WebKit-style focus 2 | 3 | @mixin tab-focus() { 4 | // WebKit-specific. Other browsers will keep their default outline style. 5 | // (Initially tried to also force default via `outline: initial`, 6 | // but that seems to erroneously remove the outline in Firefox altogether.) 7 | outline: 5px auto -webkit-focus-ring-color; 8 | outline-offset: -2px; 9 | } 10 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_table-row.scss: -------------------------------------------------------------------------------- 1 | // Tables 2 | 3 | @mixin table-row-variant($state, $background) { 4 | // Exact selectors below required to override `.table-striped` and prevent 5 | // inheritance to nested tables. 6 | .table > thead > tr, 7 | .table > tbody > tr, 8 | .table > tfoot > tr { 9 | > td.#{$state}, 10 | > th.#{$state}, 11 | &.#{$state} > td, 12 | &.#{$state} > th { 13 | background-color: $background; 14 | } 15 | } 16 | 17 | // Hover states for `.table-hover` 18 | // Note: this is not available for cells or rows within `thead` or `tfoot`. 19 | .table-hover > tbody > tr { 20 | > td.#{$state}:hover, 21 | > th.#{$state}:hover, 22 | &.#{$state}:hover > td, 23 | &:hover > .#{$state}, 24 | &.#{$state}:hover > th { 25 | background-color: darken($background, 5%); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_text-emphasis.scss: -------------------------------------------------------------------------------- 1 | // Typography 2 | 3 | // [converter] $parent hack 4 | @mixin text-emphasis-variant($parent, $color) { 5 | #{$parent} { 6 | color: $color; 7 | } 8 | a#{$parent}:hover, 9 | a#{$parent}:focus { 10 | color: darken($color, 10%); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/bootstrap/mixins/_text-overflow.scss: -------------------------------------------------------------------------------- 1 | // Text overflow 2 | // Requires inline-block or block for proper styling 3 | 4 | @mixin text-overflow() { 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | } 9 | -------------------------------------------------------------------------------- /src/stylesheets/bootstrap/readme.txt: -------------------------------------------------------------------------------- 1 | This is a copy of the stylesheets from bootstrap-sass with px units replaced with em. -------------------------------------------------------------------------------- /src/stylesheets/functions.scss: -------------------------------------------------------------------------------- 1 | @function strip-unit($num) { 2 | @return $num / ($num * 0 + 1); 3 | } 4 | -------------------------------------------------------------------------------- /src/stylesheets/loadingScreen.scss: -------------------------------------------------------------------------------- 1 | @import "variables.scss"; 2 | @import "details.scss"; 3 | @import "bootstrap-override.scss"; 4 | @import "vortex/globals"; 5 | @import "vortex/progressbar"; 6 | 7 | html, body, #content { 8 | height: 100%; 9 | margin: 0; 10 | > svg { 11 | display: none; 12 | } 13 | } 14 | 15 | #loading-screen { 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: center; 19 | align-items: center; 20 | height: 100%; 21 | color: $text-color; 22 | } 23 | 24 | #loading-screen .progressbar { 25 | width: 50%; 26 | .progressbar-labels>*:last-child { 27 | width: initial; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/stylesheets/thirdparty.scss: -------------------------------------------------------------------------------- 1 | @import "bootstrap/_bootstrap"; 2 | @import "react-select"; 3 | @import "resizer"; 4 | @import "react-sortable-tree"; 5 | @import "datepicker/datepicker"; 6 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/banner.scss: -------------------------------------------------------------------------------- 1 | .banner { 2 | display: flex; 3 | position: relative; 4 | 5 | > * { 6 | opacity: 0; 7 | width: 100%; 8 | height: 100%; 9 | &.active { 10 | opacity: 1; 11 | } 12 | 13 | transition: opacity 1000ms ease-in; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/bbcode.scss: -------------------------------------------------------------------------------- 1 | .bbcode-spoiler-tag { 2 | button { 3 | display: block; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/bebasneue.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'BebasNeue'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('BebasNeue'), local('BebasNeue-Regular'), url(assets/fonts/bebasneue_regular.woff2) format('woff2'); 6 | } 7 | 8 | @font-face { 9 | font-family: 'BebasNeue'; 10 | font-style: normal; 11 | font-weight: 300; 12 | src: local('BebasNeue-Light'), url(assets/fonts/bebasneue_light.woff2) format('woff2'); 13 | } 14 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/collapse.scss: -------------------------------------------------------------------------------- 1 | .collapse-container { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | 7 | .collapse-content { 8 | flex: 1 1 0; 9 | transition: opacity $transition-time-half; 10 | opacity: 1; 11 | display: flex; 12 | } 13 | 14 | .collapse-content-hidden { 15 | opacity: 0; 16 | } 17 | } -------------------------------------------------------------------------------- /src/stylesheets/vortex/dialog-fix-deployment.scss: -------------------------------------------------------------------------------- 1 | #fix-deployment-dialog { 2 | .modal-body { 3 | min-height: 20em; 4 | } 5 | } -------------------------------------------------------------------------------- /src/stylesheets/vortex/dialog-history.scss: -------------------------------------------------------------------------------- 1 | #history-dialog { 2 | .modal-dialog { 3 | width: 80%; 4 | } 5 | .modal-body { 6 | .history-table-container { 7 | flex: 1 1 0; 8 | overflow: auto; 9 | } 10 | table { 11 | width: 100%; 12 | } 13 | display: flex; 14 | flex-direction: column; 15 | height: 60vh; 16 | overflow: auto; 17 | } 18 | } 19 | 20 | .history-event-line { 21 | height: 2.5em; 22 | .history-event-time, 23 | .history-event-game { 24 | min-width: 10em; 25 | } 26 | } 27 | 28 | .history-event-description { 29 | padding: 0 1em; 30 | } 31 | 32 | .history-event-invalid { 33 | opacity: 0.8; 34 | } 35 | 36 | .history-event-revert { 37 | .btn { 38 | width: 100%; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/dialog-search-paths.scss: -------------------------------------------------------------------------------- 1 | .game-search-path { 2 | display: flex; 3 | > .input-group { 4 | flex: 1 1 0; 5 | } 6 | > button { 7 | margin-left: 1em; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/layout.scss: -------------------------------------------------------------------------------- 1 | .layout-container { 2 | display: flex; 3 | &.layout-fill { 4 | width: 100%; 5 | height: 100%; 6 | } 7 | } 8 | 9 | .layout-flex { 10 | >.layout-flex-inner { 11 | display: inline; 12 | &.layout-flex-fill { 13 | position: absolute; 14 | top: 0; 15 | bottom: 0; 16 | left: 0; 17 | right: 0; 18 | } 19 | } 20 | } 21 | 22 | .layout-flex { 23 | flex: 1 1 0; 24 | position: relative; 25 | overflow: hidden; 26 | } 27 | 28 | .layout-fixed { 29 | position: relative; 30 | } 31 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/page-extensions.scss: -------------------------------------------------------------------------------- 1 | #table-extensions { 2 | // prevent word wrap 3 | .table-header-cell { 4 | white-space: nowrap; 5 | } 6 | .cell-author, .cell-version { 7 | white-space: nowrap; 8 | } 9 | .header-name { 10 | // use up remaining space 11 | width: 100%; 12 | } 13 | } 14 | 15 | .description-actions > a { 16 | margin-right: 1em; 17 | } 18 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/placeholder.scss: -------------------------------------------------------------------------------- 1 | .placeholder { 2 | color: $text-color-disabled; 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: center; 6 | align-items: center; 7 | padding: $gutter-width; 8 | 9 | &.fill-parent { 10 | position: absolute; 11 | top: 0; 12 | bottom: 0; 13 | left: 0; 14 | right: 0; 15 | min-height: initial; 16 | } 17 | 18 | .placeholder-icon { 19 | width: 92px; 20 | height: 92px; 21 | } 22 | 23 | .placeholder-text { 24 | font-family: $font-family-headings; 25 | font-size: 2em; 26 | // text-transform: uppercase; 27 | } 28 | } 29 | 30 | .placeholder-container { 31 | height: 300px; 32 | position: relative; 33 | } 34 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/portal-menu.scss: -------------------------------------------------------------------------------- 1 | // these are menus (i.e. dropdown menus) that are 2 | // drawn on a separate layer so it's not cut off 3 | // by containers higher up in the hierarchy 4 | 5 | .menu-layer { 6 | position: absolute; 7 | width: 100%; 8 | height: 100%; 9 | top: 0; 10 | left: 0; 11 | pointer-events: none; 12 | z-index: $zindex-menu-layer; 13 | 14 | > * { 15 | pointer-events: initial; 16 | } 17 | } 18 | 19 | .modal-container .menu-layer { 20 | z-index: $zindex-modal + 5; 21 | } 22 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/progress.scss: -------------------------------------------------------------------------------- 1 | // "embedded" progress bar that shouldn't set itself apart from 2 | // the surroundings too much 3 | .progress-embed { 4 | // using max-height here is a bit of a hack because with react 5 | // bootstrap I apparently can't replace the .progress class, 6 | // I can just expand it, so if I set height here it has no effect 7 | max-height: 16px; 8 | box-shadow: inset 0 1px 2px rgba(0,0,0,.1); 9 | background: $gray-light; 10 | margin-bottom: 0px; 11 | border: 1px; 12 | border-style: solid; 13 | } 14 | 15 | // container around an embedded progress bar 16 | .progress-container { 17 | display: inline-block; 18 | width: 100px; 19 | vertical-align: middle; 20 | } 21 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/radial.scss: -------------------------------------------------------------------------------- 1 | .radial-progress-running { 2 | fill: $brand-secondary; 3 | } 4 | 5 | .radial-progress-paused { 6 | fill: $brand-bg; 7 | } 8 | 9 | .radial-rest { 10 | fill: $gray-light; 11 | } 12 | 13 | .radial--spin { 14 | animation-name: radial--spin; 15 | animation-duration: 1.5s; 16 | animation-iteration-count: infinite; 17 | animation-timing-function: linear 18 | } 19 | 20 | @keyframes radial--spin { 21 | from { 22 | transform: rotate(0deg); 23 | } 24 | 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } -------------------------------------------------------------------------------- /src/stylesheets/vortex/timer.scss: -------------------------------------------------------------------------------- 1 | .timer-background { 2 | stroke: $text-color-disabled; 3 | opacity: 0.5; 4 | } 5 | 6 | .timer-circle { 7 | animation-name: circle-fill; 8 | } 9 | 10 | @keyframes circle-fill { 11 | to { stroke-dasharray: 0 100; } 12 | } 13 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/tristatecheckbox.scss: -------------------------------------------------------------------------------- 1 | .tri-state-checkbox-container { 2 | display: flex; 3 | align-items: center; 4 | input[type="checkbox"] { 5 | margin: 3px 5px; 6 | } 7 | } -------------------------------------------------------------------------------- /src/stylesheets/vortex/usage.scss: -------------------------------------------------------------------------------- 1 | .usage-instructions { 2 | // position: absolute; 3 | // bottom: $gutter-width; 4 | // left: $gutter-width; 5 | background-color: $brand-bg; 6 | border: $border-width solid $border-color; 7 | padding: 4px; 8 | position: relative; 9 | &.usage-instructions-show { 10 | padding-right: 32px; 11 | } 12 | 13 | &.usage-instructions-transparent { 14 | opacity: 0.75; 15 | } 16 | 17 | .close-button { 18 | top: 0; 19 | height: 100%; 20 | } 21 | } 22 | 23 | .usage-instructions-content { 24 | display: flex; 25 | min-height: 32px; 26 | align-items: center; 27 | } 28 | -------------------------------------------------------------------------------- /src/stylesheets/vortex/window-controls.scss: -------------------------------------------------------------------------------- 1 | #window-controls { 2 | position: absolute; 3 | top: 12px; 4 | right: 16px; 5 | .window-control { 6 | width: 38px; 7 | background-color: initial; 8 | border-width: 0; 9 | 10 | &:hover { 11 | color: $brand-primary; 12 | } 13 | } 14 | 15 | .window-control#window-close:hover { 16 | color: $brand-primary; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/toJSONSchema.ts: -------------------------------------------------------------------------------- 1 | export { IPreset, IPresetsState } from './types/IPreset'; -------------------------------------------------------------------------------- /src/types/Extension.ts: -------------------------------------------------------------------------------- 1 | import { IExtensionContext, IReducerSpec } from './IExtensionContext'; 2 | 3 | export interface IExtensionReducer { 4 | path: string[]; 5 | reducer: IReducerSpec; 6 | } 7 | 8 | export type ExtensionInit = (context: IExtensionContext) => boolean; 9 | -------------------------------------------------------------------------------- /src/types/IAttributeState.ts: -------------------------------------------------------------------------------- 1 | import { SortDirection } from './SortDirection'; 2 | 3 | /** 4 | * user-configuration for mod attributes 5 | * 6 | * @export 7 | * @interface IAttributeState 8 | */ 9 | export interface IAttributeState { 10 | enabled: boolean; 11 | sortDirection: SortDirection; 12 | } 13 | -------------------------------------------------------------------------------- /src/types/IBannerOptions.ts: -------------------------------------------------------------------------------- 1 | export interface IBannerOptions { 2 | onClick?: () => void; 3 | condition?: (props: any) => boolean; 4 | props?: { [key: string]: (state: any) => any }; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/IComponentContext.ts: -------------------------------------------------------------------------------- 1 | import { IExtensionApi } from './IExtensionContext'; 2 | import { IModifiers } from './IModifiers'; 3 | 4 | /** 5 | * the context object passed along with all components 6 | * 7 | * @export 8 | * @interface IContext 9 | */ 10 | export interface IComponentContext { 11 | api: IExtensionApi; 12 | menuLayer: HTMLDivElement; 13 | getModifiers: () => IModifiers; 14 | } 15 | -------------------------------------------------------------------------------- /src/types/IDiscoveredTool.ts: -------------------------------------------------------------------------------- 1 | import { ITool } from './ITool'; 2 | 3 | export interface IDiscoveredTool extends ITool { 4 | // path to the tool (including the executable name!) 5 | path: string; 6 | hidden: boolean; 7 | custom: boolean; 8 | // working directory can be empty in which case the parent dir of the executable is used 9 | workingDirectory?: string; 10 | timestamp?: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/types/IDynDivOptions.ts: -------------------------------------------------------------------------------- 1 | export interface IDynDivOptions { 2 | onClick?: () => void; 3 | condition?: (props: any) => boolean; 4 | props?: { [key: string]: (state: any) => any }; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/IError.ts: -------------------------------------------------------------------------------- 1 | export interface IError { 2 | message: string; 3 | title?: string; 4 | subtitle?: string; 5 | code?: string; 6 | details?: string; 7 | stack?: string; 8 | extension?: string; 9 | path?: string; 10 | allowReport?: boolean; 11 | attachLog?: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /src/types/IExecInfo.ts: -------------------------------------------------------------------------------- 1 | export interface IExecInfo { 2 | execPath: string; 3 | arguments: string[]; 4 | } 5 | -------------------------------------------------------------------------------- /src/types/IExtensionProvider.ts: -------------------------------------------------------------------------------- 1 | export interface IExtensibleProps { 2 | group?: string; 3 | staticElements?: any[]; 4 | } 5 | 6 | export interface IExtendedProps { 7 | objects: any[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/types/IGameStoreEntry.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface IGameStoreEntry { 3 | appid: string; 4 | name: string; 5 | gamePath: string; 6 | gameStoreId: string; 7 | priority?: number; 8 | lastUpdated?: Date; 9 | lastUser?: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/types/II18NProps.ts: -------------------------------------------------------------------------------- 1 | import { TFunction } from '../util/i18n'; 2 | 3 | export interface II18NProps { 4 | t?: TFunction; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/IMainPage.ts: -------------------------------------------------------------------------------- 1 | import ReduxProp from '../util/ReduxProp'; 2 | 3 | import * as React from 'react'; 4 | 5 | /** 6 | * interface of a "main page", that is: a content page 7 | * displaying a lot of data and thus requiring a lot of screen 8 | * space 9 | * 10 | * @export 11 | * @interface IMainPage 12 | */ 13 | export interface IMainPage { 14 | id: string; 15 | icon: string; 16 | title: string; 17 | component: React.ComponentClass | React.StatelessComponent; 18 | propsFunc: () => any; 19 | visible: () => boolean; 20 | group: 'global' | 'per-game' | 'support' | 'hidden' | 'dashboard'; 21 | priority?: number; 22 | badge?: ReduxProp; 23 | activity?: ReduxProp; 24 | namespace?: string; 25 | onReset?: () => void; 26 | } 27 | -------------------------------------------------------------------------------- /src/types/IModifiers.ts: -------------------------------------------------------------------------------- 1 | export interface IModifiers { 2 | alt: boolean; 3 | ctrl: boolean; 4 | shift: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/ITestResult.ts: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | 3 | export type ProblemSeverity = 'warning' | 'error' | 'fatal'; 4 | 5 | export interface ITestResult { 6 | description: { 7 | short: string; 8 | long?: string; 9 | replace?: { [key: string]: any }, 10 | localize?: boolean; 11 | context?: any; 12 | }; 13 | severity: ProblemSeverity; 14 | automaticFix?: () => Promise; 15 | onRecheck?: () => Promise; 16 | } 17 | -------------------------------------------------------------------------------- /src/types/SortDirection.ts: -------------------------------------------------------------------------------- 1 | export type SortDirection = 'none' | 'asc' | 'desc'; 2 | -------------------------------------------------------------------------------- /src/types/VortexInstallType.ts: -------------------------------------------------------------------------------- 1 | // identifies how Vortex was installed. This controls its behavior around auto updating for example. 2 | // 'regular' means our own installer was used meaning Vortex itself provides capabilities for updating, 3 | // uninstalling and so on. 4 | // 'managed' means Vortex was installed through a store which is then responsible for updating or 5 | // uninstalling. 6 | type VortexInstallType = 'regular' | 'managed'; 7 | 8 | export default VortexInstallType; 9 | -------------------------------------------------------------------------------- /src/types/collections/IGameSpecificInterfaceProps.ts: -------------------------------------------------------------------------------- 1 | import { IRevision } from '@nexusmods/nexus-api'; 2 | import * as types from '../api'; 3 | 4 | export interface IGameSpecificInterfaceProps { 5 | t: types.TFunction; 6 | collection: types.IMod; 7 | revisionInfo: IRevision; 8 | } -------------------------------------------------------------------------------- /src/types/collections/api.ts: -------------------------------------------------------------------------------- 1 | import { IGameSpecificInterfaceProps } from './IGameSpecificInterfaceProps'; 2 | import * as types from '../api'; 3 | 4 | export interface ICollectionsGameSupportEntry { 5 | gameId: string; 6 | generator: (state: types.IState, 7 | gameId: string, 8 | stagingPath: string, 9 | modIds: string[], 10 | mods: { [modId: string]: types.IMod }) => Promise; 11 | 12 | parser: (api: types.IExtensionApi, 13 | gameId: string, 14 | collection: any) => Promise; 15 | 16 | interface: (props: IGameSpecificInterfaceProps) => JSX.Element; 17 | } 18 | -------------------------------------------------------------------------------- /src/util/AsyncComponent.tsx: -------------------------------------------------------------------------------- 1 | import asyncRequire from './asyncRequire'; 2 | 3 | import * as React from 'react'; 4 | 5 | /** 6 | * React Component Wrapper for async require. This requires the 7 | * component asynchronously (assuming it's the default export), 8 | * showing nothing until loading is finished. 9 | * 10 | * @export 11 | * @template T 12 | * @param {string} moduleId 13 | * @param {string} [basedir] 14 | * @returns 15 | */ 16 | export default function(moduleId: string, basedir?: string) { 17 | let mod: { 18 | default: React.ComponentClass, 19 | }; 20 | 21 | asyncRequire(moduleId, basedir) 22 | .then(modIn => mod = modIn); 23 | 24 | return (props) => { 25 | if (mod === undefined) { 26 | return null; 27 | } 28 | return ; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /src/util/LazyComponent.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as reqResolve from 'resolve'; 3 | 4 | export default function(load: () => any) { 5 | let mod: { 6 | default: React.ComponentClass, 7 | }; 8 | return (props) => { 9 | if (mod === undefined) { 10 | mod = load(); 11 | } 12 | return ; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/util/RelaxedReselectCache.ts: -------------------------------------------------------------------------------- 1 | const NULL_KEY = 'e210e05b-5b22-47ee-96d7-cfd10ae18ef9'; 2 | 3 | export class RelaxedReselectCache { 4 | private mCache: Map; 5 | constructor() { 6 | this.mCache = new Map(); 7 | } 8 | public set(key: string, selectorFn) { 9 | this.mCache.set(key ?? NULL_KEY, selectorFn); 10 | } 11 | 12 | public get(key: string) { 13 | return this.mCache.get(key ?? NULL_KEY); 14 | } 15 | 16 | public remove(key: string) { 17 | this.mCache.delete(key ?? NULL_KEY); 18 | } 19 | 20 | public clear() { 21 | this.mCache.clear(); 22 | } 23 | 24 | public isValidCacheKey() { 25 | return true; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/util/__mocks__/ExtensionProvider.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | const ext = jest.genMockFromModule('../ExtensionProvider'); 4 | 5 | function extend(registerFunc) { 6 | return (component) => { 7 | // tslint:disable-next-line:class-name 8 | return class __ExtendedComponent extends React.Component { 9 | public render() { 10 | const wrapProps = { 11 | ...this.props, 12 | objects: [], 13 | }; 14 | return React.createElement(component, wrapProps, []); 15 | } 16 | }; 17 | }; 18 | } 19 | 20 | ext['extend'] = extend; 21 | 22 | module.exports = ext; 23 | -------------------------------------------------------------------------------- /src/util/__mocks__/log.ts: -------------------------------------------------------------------------------- 1 | const ext = jest.genMockFromModule('../log'); 2 | 3 | module.exports = ext; 4 | -------------------------------------------------------------------------------- /src/util/bbcode/BrTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | class BrTag extends Tag { 5 | public toHTML(): string[] { 6 | return ['
']; 7 | } 8 | 9 | public toReact() { 10 | return
; 11 | } 12 | } 13 | 14 | export default BrTag; 15 | -------------------------------------------------------------------------------- /src/util/bbcode/FontTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | class FontTag extends Tag { 5 | public toHTML(): string[] { 6 | const font = this.params.font; 7 | 8 | return [``, this.getContent(), '']; 9 | } 10 | 11 | public toReact() { 12 | const font = this.params.font; 13 | 14 | return ( 15 | {this.getComponents()} 16 | ); 17 | } 18 | } 19 | 20 | export default FontTag; 21 | -------------------------------------------------------------------------------- /src/util/bbcode/HeadingTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | class HeadingTag extends Tag { 5 | public toHTML(): string[] { 6 | return [`

`, this.getContent(), '

']; 7 | } 8 | 9 | public toReact() { 10 | return ( 11 |

{this.getComponents()}

12 | ); 13 | } 14 | } 15 | 16 | export default HeadingTag; 17 | -------------------------------------------------------------------------------- /src/util/bbcode/IdentityTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | 3 | class IdentityTag extends Tag { 4 | public toHTML(): string[] { 5 | return [this.getContent()]; 6 | } 7 | 8 | public toReact(): React.ReactChild[] { 9 | return this.getComponents(); 10 | } 11 | } 12 | 13 | export default IdentityTag; 14 | -------------------------------------------------------------------------------- /src/util/bbcode/LineTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | class LineTag extends Tag { 5 | public toHTML(): string[] { 6 | return ['
', this.getContent()]; 7 | } 8 | 9 | public toReact() { 10 | return ( 11 |
12 |
13 | {this.getComponents()} 14 |
15 | ); 16 | } 17 | } 18 | 19 | export default LineTag; 20 | -------------------------------------------------------------------------------- /src/util/bbcode/MoreTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | import More from '../../controls/More'; 4 | 5 | class MoreTag extends Tag { 6 | public toHTML(): string[] { 7 | return []; 8 | } 9 | 10 | public toReact() { 11 | const { id, name, wikiId } = Object.keys(this.params).reduce((prev: any, par) => { 12 | prev[par] = this.params[par].replace(/^["']|["']$/g, ''); 13 | return prev; 14 | } , {}); 15 | return ( 16 | 17 | {this.getContent(true)} 18 | 19 | ); 20 | } 21 | } 22 | 23 | export default MoreTag; 24 | -------------------------------------------------------------------------------- /src/util/bbcode/SizeTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | class SizeTag extends Tag { 5 | public toHTML(): string[] { 6 | const size = this.params.size; 7 | 8 | if (isNaN(size)) { 9 | return [this.getContent()]; 10 | } 11 | 12 | return [``, this.getContent(), '']; 13 | } 14 | 15 | public toReact(): React.ReactChild[] { 16 | const size = this.params.size; 17 | 18 | if (isNaN(size)) { 19 | return this.getComponents(); 20 | } 21 | 22 | return [( 23 | {this.getComponents()} 24 | )]; 25 | } 26 | 27 | private calc(sizeFactor: number): string { 28 | return `${1 + sizeFactor * 0.1}rem`; 29 | } 30 | } 31 | 32 | export default SizeTag; 33 | -------------------------------------------------------------------------------- /src/util/bbcode/StyleTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | class StyleTag extends Tag { 5 | public toHTML(): string[] { 6 | const style = this.params.style; 7 | 8 | return [``, this.getContent(), '']; 9 | } 10 | 11 | public toReact() { 12 | const style = this.params.style; 13 | 14 | return ( 15 | {this.getComponents()} 16 | ); 17 | } 18 | } 19 | 20 | export default StyleTag; -------------------------------------------------------------------------------- /src/util/bbcode/SvgTag.tsx: -------------------------------------------------------------------------------- 1 | import Icon from '../../controls/Icon'; 2 | 3 | import { Tag } from 'bbcode-to-react'; 4 | import * as React from 'react'; 5 | 6 | class SvgTag extends Tag { 7 | public toHTML(): string[] { 8 | return [` 12 | 13 | `]; 14 | } 15 | 16 | public toReact() { 17 | return ( 18 | 19 | ); 20 | } 21 | } 22 | 23 | export default SvgTag; 24 | -------------------------------------------------------------------------------- /src/util/bbcode/TooltipTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | function nop() { 5 | // nop 6 | } 7 | 8 | class TooltipTag extends Tag { 9 | public toHTML(): string[] { 10 | return [this.getContent()]; 11 | } 12 | 13 | public toReact() { 14 | const { tooltip } = this.params; 15 | return {this.getComponents()}; 16 | } 17 | } 18 | 19 | export default TooltipTag; 20 | -------------------------------------------------------------------------------- /src/util/bbcode/YoutubeTag.tsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'bbcode-to-react'; 2 | import * as React from 'react'; 3 | 4 | class YoutubeTag extends Tag { 5 | public toHTML(): string[] { 6 | return [`