diff --git a/src/components/custom-world-home/CustomWorldWorkTabs.tsx b/src/components/custom-world-home/CustomWorldWorkTabs.tsx
index 1eb6cc92..9b50c18d 100644
--- a/src/components/custom-world-home/CustomWorldWorkTabs.tsx
+++ b/src/components/custom-world-home/CustomWorldWorkTabs.tsx
@@ -1,3 +1,5 @@
+import { PlatformSegmentedTabs } from '../common/PlatformSegmentedTabs';
+
export type CustomWorldWorkFilter = 'all' | 'draft' | 'published';
const FILTER_OPTIONS: Array<{
@@ -22,33 +24,42 @@ export function CustomWorldWorkTabs({
publishedCount,
onChange,
}: CustomWorldWorkTabsProps) {
- return (
-
- {FILTER_OPTIONS.map((option) => {
- const count =
- option.id === 'draft'
- ? draftCount
- : option.id === 'published'
- ? publishedCount
- : draftCount + publishedCount;
+ const filterTabs = FILTER_OPTIONS.map((option) => {
+ const count =
+ option.id === 'draft'
+ ? draftCount
+ : option.id === 'published'
+ ? publishedCount
+ : draftCount + publishedCount;
- return (
- onChange(option.id)}
- className={`platform-mobile-home-channel shrink-0 ${activeFilter === option.id ? 'platform-mobile-home-channel--active' : ''}`}
- >
- {option.label} {count}
-
- );
- })}
-
+ return {
+ id: option.id,
+ label: `${option.label} ${count}`,
+ };
+ });
+
+ return (
+
+ [
+ 'platform-mobile-home-channel shrink-0 !min-h-8 !rounded-none !border-0 !bg-transparent !px-0 !shadow-none hover:!bg-transparent',
+ active ? 'platform-mobile-home-channel--active' : null,
+ ]
+ .filter(Boolean)
+ .join(' ')
+ }
+ />
);
}
diff --git a/src/components/platform-entry/PlatformDraftGenerationPointNoticeDialog.test.tsx b/src/components/platform-entry/PlatformDraftGenerationPointNoticeDialog.test.tsx
new file mode 100644
index 00000000..789ac7ee
--- /dev/null
+++ b/src/components/platform-entry/PlatformDraftGenerationPointNoticeDialog.test.tsx
@@ -0,0 +1,49 @@
+/* @vitest-environment jsdom */
+
+import { fireEvent, render, screen } from '@testing-library/react';
+import { expect, test, vi } from 'vitest';
+
+import {
+ PlatformDraftGenerationPointNoticeDialog,
+} from './PlatformDraftGenerationPointNoticeDialog';
+
+test('renders the insufficient-points notice with the shared blocking copy', () => {
+ const onClose = vi.fn();
+
+ render(
+ ,
+ );
+
+ expect(screen.getByRole('dialog', { name: '泥点不足' })).toBeTruthy();
+ expect(screen.getByText('本次需要 30 泥点,当前 12 泥点。')).toBeTruthy();
+ expect(
+ screen.getByText('当前表单不会丢失,关闭后可继续编辑或补足泥点再继续。'),
+ ).toBeTruthy();
+
+ fireEvent.click(screen.getByRole('button', { name: '知道了' }));
+ expect(onClose).toHaveBeenCalledTimes(1);
+});
+
+test('renders the balance-load-failed notice without the amber icon override', () => {
+ render(
+ {}}
+ />,
+ );
+
+ const dialog = screen.getByRole('dialog', { name: '读取泥点余额失败' });
+
+ expect(screen.getByText('请稍后重试。')).toBeTruthy();
+ expect(
+ screen.getByText('当前表单不会丢失,关闭后可继续编辑,稍后再试。'),
+ ).toBeTruthy();
+ expect(dialog.innerHTML).not.toContain('bg-amber-100/80');
+});
diff --git a/src/components/platform-entry/PlatformDraftGenerationPointNoticeDialog.tsx b/src/components/platform-entry/PlatformDraftGenerationPointNoticeDialog.tsx
new file mode 100644
index 00000000..97393a48
--- /dev/null
+++ b/src/components/platform-entry/PlatformDraftGenerationPointNoticeDialog.tsx
@@ -0,0 +1,79 @@
+import { PlatformAcknowledgeStatusDialog } from '../common/PlatformAcknowledgeStatusDialog';
+
+export type DraftGenerationPointNotice =
+ | {
+ kind: 'insufficient-points';
+ requiredPoints: number;
+ currentPoints: number;
+ }
+ | {
+ kind: 'balance-load-failed';
+ };
+
+type PlatformDraftGenerationPointNoticeDialogProps = {
+ notice: DraftGenerationPointNotice | null;
+ onClose: () => void;
+ overlayClassName?: string;
+ panelClassName?: string;
+ zIndexClassName?: string;
+};
+
+function resolveDraftGenerationPointNoticeTitle(
+ notice: DraftGenerationPointNotice,
+) {
+ return notice.kind === 'balance-load-failed' ? '读取泥点余额失败' : '泥点不足';
+}
+
+function resolveDraftGenerationPointNoticeDescription(
+ notice: DraftGenerationPointNotice,
+) {
+ return notice.kind === 'balance-load-failed'
+ ? '当前表单不会丢失,关闭后可继续编辑,稍后再试。'
+ : '当前表单不会丢失,关闭后可继续编辑或补足泥点再继续。';
+}
+
+function resolveDraftGenerationPointNoticeMessage(
+ notice: DraftGenerationPointNotice,
+) {
+ return notice.kind === 'balance-load-failed'
+ ? '请稍后重试。'
+ : `本次需要 ${notice.requiredPoints} 泥点,当前 ${notice.currentPoints} 泥点。`;
+}
+
+/**
+ * 创作前置泥点提示弹层。
+ * 只承接平台入口里“泥点不足 / 读取余额失败”这类阻断提示,避免 FlowShell 直接拼底层状态弹窗。
+ */
+export function PlatformDraftGenerationPointNoticeDialog({
+ notice,
+ onClose,
+ overlayClassName,
+ panelClassName,
+ zIndexClassName,
+}: PlatformDraftGenerationPointNoticeDialogProps) {
+ if (!notice) {
+ return null;
+ }
+
+ return (
+
+ {resolveDraftGenerationPointNoticeMessage(notice)}
+
+ );
+}
diff --git a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx
index e09c25f6..ccda5196 100644
--- a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx
+++ b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx
@@ -498,6 +498,10 @@ import {
EDUTAINMENT_HIDDEN_MESSAGE,
filterGeneralPublicWorks,
} from './platformEdutainmentVisibility';
+import {
+ PlatformDraftGenerationPointNoticeDialog,
+ type DraftGenerationPointNotice,
+} from './PlatformDraftGenerationPointNoticeDialog';
import { PlatformEntryCreationTypeModal } from './PlatformEntryCreationTypeModal';
import type { PlatformCreationTypeId } from './platformEntryCreationTypes';
import {
@@ -1419,10 +1423,8 @@ export function PlatformEntryFlowShellImpl({
: 'platform-theme--light';
const isDesktopLayout = usePlatformDesktopLayout();
const [showCreationTypeModal, setShowCreationTypeModal] = useState(false);
- const [draftGenerationPointNotice, setDraftGenerationPointNotice] = useState<{
- title: string;
- message: string;
- } | null>(null);
+ const [draftGenerationPointNotice, setDraftGenerationPointNotice] =
+ useState(null);
const [selectedDetailEntry, setSelectedDetailEntry] =
useState | null>(null);
const [selectedPublicWorkDetail, setSelectedPublicWorkDetail] =
@@ -2246,14 +2248,14 @@ export function PlatformEntryFlowShellImpl({
}
setDraftGenerationPointNotice({
- title: '泥点不足',
- message: `本次需要 ${pointsCost} 泥点,当前 ${walletBalance} 泥点。`,
+ kind: 'insufficient-points',
+ requiredPoints: pointsCost,
+ currentPoints: walletBalance,
});
return false;
} catch {
setDraftGenerationPointNotice({
- title: '读取泥点余额失败',
- message: '请稍后重试。',
+ kind: 'balance-load-failed',
});
return false;
}
@@ -4364,11 +4366,6 @@ export function PlatformEntryFlowShellImpl({
barkBattleDraftGenerationPointCost,
ensureEnoughDraftGenerationPointsFromServer,
]);
- const draftGenerationPointNoticeDescription = draftGenerationPointNotice
- ? draftGenerationPointNotice.title === '读取泥点余额失败'
- ? '当前表单不会丢失,关闭后可继续编辑,稍后再试。'
- : '当前表单不会丢失,关闭后可继续编辑或补足泥点再继续。'
- : undefined;
const recoverCompletedPuzzleDraftGeneration = useCallback(
async ({
sessionId,
@@ -16997,25 +16994,12 @@ export function PlatformEntryFlowShellImpl({
}}
/>
) : null}
- setDraftGenerationPointNotice(null)}
- showHeader
- showCloseButton
- closeOnBackdrop
overlayClassName={`platform-theme ${platformThemeClass} !items-center`}
panelClassName="platform-remap-surface rounded-[1.75rem]"
- iconClassName={
- draftGenerationPointNotice?.title === '读取泥点余额失败'
- ? undefined
- : 'bg-amber-100/80 text-amber-600'
- }
- >
- {draftGenerationPointNotice?.message}
-
+ />
) : null}
- {isLoading ? (
-
- {Array.from({ length: 4 }).map((_, index) => (
-
- ))}
-
- ) : hasArchiveEntries || hasPlayedWorks ? (
+
+ {Array.from({ length: 4 }).map((_, index) => (
+
+ ))}
+
+ }
+ isEmpty={!hasArchiveEntries && !hasPlayedWorks}
+ emptyState={
+