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