+
+ {t(
+ "Enter a name for your new mod. This will create an empty mod folder in your staging directory where you can add files manually.",
+ )}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default AddModModal;
diff --git a/src/extensions/add_new_mod/index.ts b/src/extensions/add_new_mod/index.ts
new file mode 100644
index 0000000000..0c977ec2de
--- /dev/null
+++ b/src/extensions/add_new_mod/index.ts
@@ -0,0 +1,37 @@
+import type { IExtensionContext } from "../../types/IExtensionContext";
+
+import AddModDialog from "./components/AddModDialog";
+import { showAddModDialog } from "./actions/session";
+import { sessionReducer } from "./reducers/session";
+
+/**
+ * Entry point for the add_new_mod extension.
+ * Registers a "Create new mod" action that opens a styled modal dialog
+ * allowing users to create empty mods for manual file management.
+ */
+function init(context: IExtensionContext): boolean {
+ // Register the session reducer for dialog visibility state
+ context.registerReducer(["session", "addNewMod"], sessionReducer);
+
+ // Register the dialog component
+ context.registerDialog("add-new-mod", AddModDialog, () => ({
+ api: context.api,
+ }));
+
+ // Register the toolbar action
+ context.registerAction(
+ "mod-icons",
+ 50,
+ "add",
+ {},
+ "Create new mod",
+ () => {
+ context.api.store?.dispatch(showAddModDialog(true));
+ },
+ () => true,
+ );
+
+ return true;
+}
+
+export default init;
diff --git a/src/extensions/add_new_mod/reducers/session.ts b/src/extensions/add_new_mod/reducers/session.ts
new file mode 100644
index 0000000000..db89eaed4f
--- /dev/null
+++ b/src/extensions/add_new_mod/reducers/session.ts
@@ -0,0 +1,18 @@
+import type { IReducerSpec } from "../../../types/IExtensionContext";
+import { setSafe } from "../../../util/storeHelper";
+
+import * as actions from "../actions/session";
+
+/**
+ * Reducer for the add_new_mod extension session state
+ */
+export const sessionReducer: IReducerSpec = {
+ reducers: {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ [actions.showAddModDialog as any]: (state, payload: boolean) =>
+ setSafe(state, ["showDialog"], payload),
+ },
+ defaults: {
+ showDialog: false,
+ },
+};
diff --git a/src/extensions/add_new_mod/util/createMod.ts b/src/extensions/add_new_mod/util/createMod.ts
new file mode 100644
index 0000000000..fca386f514
--- /dev/null
+++ b/src/extensions/add_new_mod/util/createMod.ts
@@ -0,0 +1,75 @@
+import type { IExtensionApi } from "../../../types/IExtensionContext";
+import type { IMod } from "../../mod_management/types/IMod";
+
+import { addMod } from "../../mod_management/actions/mods";
+import * as fs from "../../../util/fs";
+import { log } from "../../../util/log";
+import opn from "../../../util/opn";
+import { activeGameId, installPath } from "../../../util/selectors";
+
+import * as path from "path";
+
+/**
+ * Creates a new empty mod with the given name
+ * @param api The extension API
+ * @param name The name for the new mod
+ */
+export async function createNewMod(
+ api: IExtensionApi,
+ name: string,
+): Promise