Refactor environment selector with grouped options and descriptions

This commit is contained in:
CPTProgrammer 2026-07-16 11:18:20 +08:00
parent 269e7024a2
commit 7173ef1149
No known key found for this signature in database
2 changed files with 140 additions and 30 deletions

View File

@ -20,6 +20,8 @@ import {
getModrinthLoaders,
getModrinthEnvironments,
getCurseForgeMeta,
type EnvironmentGroup,
EnvironmentOption,
} from "@/services/meta";
import {
scanMcPropertiesDir,
@ -327,12 +329,10 @@ function useModrinthLoaders(): {
function useModrinthEnvironments(): {
loading: boolean;
options: { value: string; label: string }[];
options: EnvironmentGroup[];
} {
const [loading, setLoading] = useState(true);
const [options, setOptions] = useState<
{ value: string; label: string }[]
>([]);
const [options, setOptions] = useState<EnvironmentGroup[]>([]);
useEffect(() => {
let cancelled = false;
@ -507,8 +507,8 @@ function ConfigModalForm({
const { token } = theme.useToken();
// Each Select loads its own data independently
const mrLoaders = useModrinthLoaders();
const mrEnvs = useModrinthEnvironments();
const mrLoaders = useModrinthLoaders();
const cfMeta = useCurseforgeMeta();
const sortedMrOptions = useMemo(() => {
@ -551,22 +551,19 @@ function ConfigModalForm({
filename_format: "modname-${version}-mc${mc_version}.jar",
source_filename_format: "modname-${version}-mc${mc_version}-sources.jar",
modrinth: {
project_id: "",
version_name:
"ModName v${version} for Minecraft ${mc_version_range}",
version: "${version}-mc${mc_version}",
loaders: [],
environment: "client_and_server",
dependencies: [],
} as Config["modrinth"],
} as Partial<Config["modrinth"]>,
curseforge: {
project_id: 0,
version_name: "#{filename_format}",
environment: [],
loaders: [],
relations: { projects: [] },
} as Config["curseforge"],
} as Partial<ConfigValues>);
} as Partial<Config["curseforge"]>,
});
}
}, [mode, initialConfig, form]);
@ -755,6 +752,25 @@ function ConfigModalForm({
placeholder="选择运行环境"
loading={mrEnvs.loading}
options={mrEnvs.options}
optionRender={(option) => {
const desc = (option.data as unknown as EnvironmentOption).description;
return (
<div>
<div>{option.label}</div>
{desc && (
<div
style={{
fontSize: token.fontSizeSM,
color: token.colorTextDescription,
whiteSpace: "wrap",
}}
>
{desc}
</div>
)}
</div>
);
}}
notFoundContent={
mrEnvs.loading ? "加载中…" : "无可用选项"
}

View File

@ -4,21 +4,118 @@ import { modrinthClient, curseforgeClient } from "./clients";
import { getLoaders, getGameVersions as getModrinthGameVersions } from "@/lib/modrinth";
import { getVersionTypes, getGameVersions, getMinecraftVersions } from "@/lib/curseforge";
import { SemVer } from "@/lib/utils/templates/semver";
import { Environment, EnvironmentSchema } from "@/types";
import { Environment } from "@/types";
const ENVIRONMENT_LABELS: Record<Environment, string> = {
unknown: "Unknown environment",
client_only: "Client-side only",
server_only: "Server-side only (singleplayer compatible)",
dedicated_server_only: "Dedicated server only",
client_and_server: "Required on both",
server_only_client_optional: "Optional on client",
client_only_server_optional: "Optional on server",
client_or_server_prefers_both: "Optional on both (prefers both)",
client_or_server: "Optional on both (either side)",
singleplayer_only: "Singleplayer only",
const ENVIRONMENT_DESCRIPTIONS: Record<Environment, string> = {
client_only:
"All functionality is done client-side and is compatible with vanilla servers.",
server_only:
"All functionality is done server-side and is compatible with vanilla clients. Also works on the internal server in singleplayer.",
dedicated_server_only:
"All functionality is done server-side and is compatible with vanilla clients. Only works on dedicated servers.",
client_and_server: "Required on both the client and server.",
server_only_client_optional:
"Most functionality is server-side, but installing it on the client enables enhanced functionality.",
client_only_server_optional:
"Most functionality is client-side, but installing it on the server enables enhanced functionality.",
client_or_server_prefers_both:
"Has some functionality on both the client and server, even if only partially. Installing it on both leads to the best experience.",
client_or_server:
"Has some functionality on both the client and server, even if only partially.",
singleplayer_only:
"Only functions in Singleplayer or when not connected to a Multiplayer server.",
unknown: "The environment for this version could not be determined.",
};
export interface EnvironmentOption {
value: Environment;
label: string;
description: string;
}
export interface EnvironmentGroup {
label: string;
options: EnvironmentOption[];
}
const ENVIRONMENT_GROUPS: EnvironmentGroup[] = [
{
label: "Client-side only",
options: [
{
value: "client_only",
label: "Client-side only",
description: ENVIRONMENT_DESCRIPTIONS.client_only,
},
],
},
{
label: "Server-side only",
options: [
{
value: "server_only",
label: "Works in singleplayer too",
description: ENVIRONMENT_DESCRIPTIONS.server_only,
},
{
value: "dedicated_server_only",
label: "Dedicated server only",
description: ENVIRONMENT_DESCRIPTIONS.dedicated_server_only,
},
],
},
{
label: "Client and server",
options: [
{
value: "client_and_server",
label: "Required on both",
description: ENVIRONMENT_DESCRIPTIONS.client_and_server,
},
{
value: "server_only_client_optional",
label: "Optional on client",
description: ENVIRONMENT_DESCRIPTIONS.server_only_client_optional,
},
{
value: "client_only_server_optional",
label: "Optional on server",
description: ENVIRONMENT_DESCRIPTIONS.client_only_server_optional,
},
{
value: "client_or_server_prefers_both",
label: "Optional on both, works best when installed on both sides",
description: ENVIRONMENT_DESCRIPTIONS.client_or_server_prefers_both,
},
{
value: "client_or_server",
label: "Optional on both, works the same if installed on either side",
description: ENVIRONMENT_DESCRIPTIONS.client_or_server,
},
],
},
{
label: "Singleplayer only",
options: [
{
value: "singleplayer_only",
label: "Singleplayer only",
description: ENVIRONMENT_DESCRIPTIONS.singleplayer_only,
},
],
},
{
label: "Other",
options: [
{
value: "unknown",
label: "Unknown environment",
description: ENVIRONMENT_DESCRIPTIONS.unknown,
},
],
},
];
/**
* Modrinth
* ConfigModal loaders
@ -40,14 +137,11 @@ export async function getModrinthMcVersions(): Promise<string[]> {
}
/**
* Modrinth Ant Design Select
* 使 OptGroup Client / Server / Both / Other
* Modrinth Ant Design OptGroup
* Modrinth UI environments.ts
*/
export async function getModrinthEnvironments() {
return EnvironmentSchema.options.map((value) => ({
value,
label: ENVIRONMENT_LABELS[value],
}));
export async function getModrinthEnvironments(): Promise<EnvironmentGroup[]> {
return ENVIRONMENT_GROUPS;
}
/**