Refactor environment selector with grouped options and descriptions
This commit is contained in:
parent
269e7024a2
commit
7173ef1149
@ -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 ? "加载中…" : "无可用选项"
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user