Use theme tokens for spacing and sizing and update PublishModal
This commit is contained in:
parent
5f6cab6529
commit
7bb932910a
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useCallback } from "react";
|
||||
import { Typography, Space, Card, Button } from "antd";
|
||||
import { Typography, Space, Card, Button, theme } from "antd";
|
||||
import { CloudUploadOutlined } from "@ant-design/icons";
|
||||
import { ConfigSelector } from "./ConfigSelector";
|
||||
import { VersionTable } from "./VersionTable";
|
||||
@ -16,6 +16,7 @@ interface MainPageProps {
|
||||
}
|
||||
|
||||
export function MainPage({ initialConfigs }: MainPageProps) {
|
||||
const { token } = theme.useToken();
|
||||
const [configs, setConfigs] =
|
||||
useState<{ name: string; file: string }[]>(initialConfigs);
|
||||
const [selectedConfigFile, setSelectedConfigFile] = useState<string | null>(
|
||||
@ -67,11 +68,11 @@ export function MainPage({ initialConfigs }: MainPageProps) {
|
||||
style={{
|
||||
maxWidth: 900,
|
||||
margin: "40px auto",
|
||||
padding: "0 24px",
|
||||
padding: `0 ${token.paddingLG}px`,
|
||||
}}
|
||||
>
|
||||
{/* Page header */}
|
||||
<Title level={2} style={{ marginBottom: 24 }}>
|
||||
<Title level={2} style={{ marginBottom: token.marginLG }}>
|
||||
Mod Releaser
|
||||
</Title>
|
||||
|
||||
@ -99,7 +100,7 @@ export function MainPage({ initialConfigs }: MainPageProps) {
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
marginTop: 24,
|
||||
marginTop: token.marginLG,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
Progress,
|
||||
Typography,
|
||||
Empty,
|
||||
theme,
|
||||
} from "antd";
|
||||
import { ReloadOutlined } from "@ant-design/icons";
|
||||
import type { BaseVersion, Config, UploadReleaseType } from "@/types";
|
||||
@ -68,6 +69,7 @@ export function PublishModal({
|
||||
project,
|
||||
onClose,
|
||||
}: PublishModalProps) {
|
||||
const { token } = theme.useToken();
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
|
||||
// Version selection
|
||||
@ -81,14 +83,19 @@ export function PublishModal({
|
||||
"release",
|
||||
);
|
||||
|
||||
// Progress
|
||||
// Progress & result
|
||||
const [publishing, setPublishing] = useState(false);
|
||||
const [publishDone, setPublishDone] = useState(false);
|
||||
const [progress, setProgress] = useState<
|
||||
Record<typeof platforms[number], { done: number; total: number }>
|
||||
>({
|
||||
modrinth: { done: 0, total: 0 },
|
||||
curseforge: { done: 0, total: 0 }
|
||||
curseforge: { done: 0, total: 0 },
|
||||
});
|
||||
const [publishResult, setPublishResult] = useState<{
|
||||
success: number;
|
||||
failed: number;
|
||||
} | null>(null);
|
||||
|
||||
// Platform existing versions — loaded when modal opens
|
||||
const [loadingExisting, setLoadingExisting] = useState(false);
|
||||
@ -133,7 +140,7 @@ export function PublishModal({
|
||||
}
|
||||
setSelectedVersions(preselected);
|
||||
}
|
||||
setCurrentStep((prev) => Math.min(prev + 1, 1));
|
||||
setCurrentStep((prev) => Math.min(prev + 1, 2));
|
||||
}, [currentStep, publishVersions]);
|
||||
|
||||
const handlePrev = useCallback(() => {
|
||||
@ -142,7 +149,12 @@ export function PublishModal({
|
||||
|
||||
const handleConfirmPublish = useCallback(async () => {
|
||||
setPublishing(true);
|
||||
// TODO: Call tRPC mutation to publish
|
||||
setPublishDone(false);
|
||||
setPublishResult(null);
|
||||
setCurrentStep(2);
|
||||
// TODO: Call tRPC mutation to publish, update progress & result
|
||||
setPublishResult({ success: 0, failed: 0 });
|
||||
setPublishDone(true);
|
||||
setPublishing(false);
|
||||
}, []);
|
||||
|
||||
@ -152,6 +164,8 @@ export function PublishModal({
|
||||
setSelectedVersions(new Set());
|
||||
setChangelog("");
|
||||
setVersionType("release");
|
||||
setPublishResult(null);
|
||||
setPublishDone(false);
|
||||
onClose();
|
||||
}, [publishing, onClose]);
|
||||
|
||||
@ -233,7 +247,7 @@ export function PublishModal({
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 16,
|
||||
marginBottom: token.margin,
|
||||
}}
|
||||
>
|
||||
<Text strong>选择要发布的版本</Text>
|
||||
@ -250,9 +264,9 @@ export function PublishModal({
|
||||
{loadingExisting ? (
|
||||
<div style={{ textAlign: "center", padding: 40 }}>加载中…</div>
|
||||
) : (
|
||||
<Row gutter={16}>
|
||||
<Row gutter={token.margin}>
|
||||
<Col span={12}>
|
||||
<Text strong style={{ display: "block", marginBottom: 8 }}>
|
||||
<Text strong style={{ display: "block", marginBottom: token.marginXS }}>
|
||||
Modrinth
|
||||
</Text>
|
||||
{publishVersions.length > 0 ? (
|
||||
@ -268,7 +282,7 @@ export function PublishModal({
|
||||
)}
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Text strong style={{ display: "block", marginBottom: 8 }}>
|
||||
<Text strong style={{ display: "block", marginBottom: token.marginXS }}>
|
||||
CurseForge
|
||||
</Text>
|
||||
{publishVersions.length > 0 ? (
|
||||
@ -292,6 +306,49 @@ export function PublishModal({
|
||||
// --------------- Render: Step 2 — Publish Settings ---------------
|
||||
|
||||
const renderStep2 = () => {
|
||||
return (
|
||||
<div>
|
||||
{/* Changelog */}
|
||||
<div style={{ marginBottom: token.marginLG }}>
|
||||
<Text strong style={{ display: "block", marginBottom: token.marginSM }}>
|
||||
Changelog (Markdown)
|
||||
</Text>
|
||||
{/* TODO: Replace with @uiw/react-md-editor */}
|
||||
<textarea
|
||||
style={{
|
||||
width: "100%",
|
||||
minHeight: 160,
|
||||
border: `1px solid ${token.colorBorder}`,
|
||||
borderRadius: token.borderRadius,
|
||||
padding: token.paddingSM,
|
||||
fontFamily: token.fontFamilyCode ?? "monospace",
|
||||
fontSize: token.fontSizeSM,
|
||||
}}
|
||||
placeholder="输入 Markdown 格式的更新日志…"
|
||||
value={changelog}
|
||||
onChange={(e) => setChangelog(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Version type */}
|
||||
<div>
|
||||
<Text strong style={{ display: "block", marginBottom: token.marginSM }}>
|
||||
版本类型
|
||||
</Text>
|
||||
<Select
|
||||
value={versionType}
|
||||
onChange={(v) => setVersionType(v)}
|
||||
style={{ width: 160 }}
|
||||
options={RELEASE_TYPES}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// --------------- Render: Step 3 — Progress & Result ---------------
|
||||
|
||||
const renderStep3 = () => {
|
||||
const hasModrinth = publishVersions.some(
|
||||
(v) =>
|
||||
!v.existsModrinth &&
|
||||
@ -305,75 +362,58 @@ export function PublishModal({
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Changelog */}
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<Text strong style={{ display: "block", marginBottom: 8 }}>
|
||||
Changelog (Markdown)
|
||||
</Text>
|
||||
{/* TODO: Replace with @uiw/react-md-editor */}
|
||||
<textarea
|
||||
{/* Progress bars */}
|
||||
<div style={{ marginBottom: token.marginLG }}>
|
||||
{hasModrinth && (
|
||||
<div style={{ marginBottom: token.marginSM }}>
|
||||
<Text>Modrinth: </Text>
|
||||
<Progress
|
||||
percent={Math.round(
|
||||
(progress.modrinth.done /
|
||||
Math.max(progress.modrinth.total, 1)) *
|
||||
100,
|
||||
)}
|
||||
format={() =>
|
||||
`${progress.modrinth.done} / ${progress.modrinth.total}`
|
||||
}
|
||||
style={{ width: "80%" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{hasCurseforge && (
|
||||
<div>
|
||||
<Text>CurseForge: </Text>
|
||||
<Progress
|
||||
percent={Math.round(
|
||||
(progress.curseforge.done /
|
||||
Math.max(progress.curseforge.total, 1)) *
|
||||
100,
|
||||
)}
|
||||
format={() =>
|
||||
`${progress.curseforge.done} / ${progress.curseforge.total}`
|
||||
}
|
||||
style={{ width: "80%" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Result */}
|
||||
{publishDone && publishResult && (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
minHeight: 160,
|
||||
border: "1px solid #d9d9d9",
|
||||
borderRadius: 6,
|
||||
padding: 8,
|
||||
fontFamily: "monospace",
|
||||
fontSize: 13,
|
||||
background: token.colorSuccessBg,
|
||||
border: `1px solid ${token.colorSuccessBorder}`,
|
||||
borderRadius: token.borderRadius,
|
||||
padding: token.padding,
|
||||
}}
|
||||
placeholder="输入 Markdown 格式的更新日志…"
|
||||
value={changelog}
|
||||
onChange={(e) => setChangelog(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Version type */}
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<Text strong style={{ display: "block", marginBottom: 8 }}>
|
||||
版本类型
|
||||
</Text>
|
||||
<Select
|
||||
value={versionType}
|
||||
onChange={(v) => setVersionType(v)}
|
||||
style={{ width: 160 }}
|
||||
options={RELEASE_TYPES}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Publishing progress */}
|
||||
{publishing && (
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
{hasModrinth && (
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text>Modrinth: </Text>
|
||||
<Progress
|
||||
percent={Math.round(
|
||||
(progress.modrinth.done / Math.max(progress.modrinth.total, 1)) *
|
||||
100,
|
||||
)}
|
||||
format={() =>
|
||||
`${progress.modrinth.done} / ${progress.modrinth.total}`
|
||||
}
|
||||
style={{ width: "80%" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{hasCurseforge && (
|
||||
<div>
|
||||
<Text>CurseForge: </Text>
|
||||
<Progress
|
||||
percent={Math.round(
|
||||
(progress.curseforge.done /
|
||||
Math.max(progress.curseforge.total, 1)) *
|
||||
100,
|
||||
)}
|
||||
format={() =>
|
||||
`${progress.curseforge.done} / ${progress.curseforge.total}`
|
||||
}
|
||||
style={{ width: "80%" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<Text strong>发布结果</Text>
|
||||
<div style={{ marginTop: token.marginSM }}>
|
||||
<Text>
|
||||
成功 {publishResult.success} 个,失败 {publishResult.failed} 个
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -392,17 +432,21 @@ export function PublishModal({
|
||||
footer={
|
||||
publishing ? null : (
|
||||
<Space>
|
||||
{currentStep > 0 && (
|
||||
{currentStep > 0 && currentStep < 2 && (
|
||||
<Button onClick={handlePrev}>上一步</Button>
|
||||
)}
|
||||
{currentStep < 1 ? (
|
||||
{currentStep === 0 ? (
|
||||
<Button type="primary" onClick={handleNext}>
|
||||
下一步
|
||||
</Button>
|
||||
) : (
|
||||
) : currentStep === 1 ? (
|
||||
<Button type="primary" onClick={handleConfirmPublish}>
|
||||
确认发布
|
||||
</Button>
|
||||
) : (
|
||||
<Button type="primary" onClick={handleClose}>
|
||||
关闭
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
)
|
||||
@ -415,10 +459,15 @@ export function PublishModal({
|
||||
items={[
|
||||
{ title: "版本选择" },
|
||||
{ title: "发布设置" },
|
||||
{ title: "发布进度" },
|
||||
]}
|
||||
/>
|
||||
|
||||
{currentStep === 0 ? renderStep1() : renderStep2()}
|
||||
{currentStep === 0
|
||||
? renderStep1()
|
||||
: currentStep === 1
|
||||
? renderStep2()
|
||||
: renderStep3()}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useMemo, useCallback } from "react";
|
||||
import { Table, Empty, Tag, Typography, Select, Flex } from "antd";
|
||||
import { Table, Empty, Tag, Typography, Select, Flex, theme } from "antd";
|
||||
import type { ParsedProject } from "@/services/project";
|
||||
import { computeVersionRanges, collectAutoRange, type McVersionEntry } from "@/lib/utils/mcVersion";
|
||||
import { getMcVersionUnion } from "@/services/meta";
|
||||
@ -24,6 +24,7 @@ export function VersionTable({
|
||||
loading,
|
||||
onLoadingChange,
|
||||
}: VersionTableProps) {
|
||||
const { token } = theme.useToken();
|
||||
// ── MC version union from both platforms ──
|
||||
const [allMcVersions, setAllMcVersions] = useState<string[]>([]);
|
||||
|
||||
@ -164,7 +165,7 @@ export function VersionTable({
|
||||
<Tag color="blue">{entry.wildcard}</Tag>
|
||||
<Typography.Text
|
||||
type="secondary"
|
||||
style={{ fontSize: 12, whiteSpace: "nowrap" }}
|
||||
style={{ fontSize: token.fontSizeSM, whiteSpace: "nowrap" }}
|
||||
>
|
||||
截止
|
||||
</Typography.Text>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user