style(web): 用户工作台 - 主操作改描边并统一弹窗浮层样式
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,6 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { keepPreviousData, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { App, Button, Drawer, Dropdown, Form, Input, Modal, Popconfirm, Progress, Select, Space, Tag, Typography } from "antd";
|
||||
import type { MenuProps } from "antd";
|
||||
import { IconButton } from "@/components/ui/base/buttons";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
import { CollectionGrid, ListToolbar, PageHeader, PaginationBar, WorkspacePage } from "@/components/layout/workspace-page";
|
||||
@@ -551,7 +550,7 @@ export default function AssetsPage() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button className="library-primary-action" type="primary" icon={<Plus className="size-3.5" />} onClick={openCreate}>
|
||||
<Button icon={<Plus className="size-3.5" />} onClick={openCreate}>
|
||||
新增素材
|
||||
</Button>
|
||||
<Button icon={<Images className="size-3.5" />} onClick={() => setBatchUploadOpen(true)}>
|
||||
@@ -560,7 +559,7 @@ export default function AssetsPage() {
|
||||
<Button icon={<FolderOpen className="size-3.5" />} onClick={() => navigate("/plugins/eagle")}>
|
||||
Eagle 素材库
|
||||
</Button>
|
||||
<IconButton variant="solid" icon={Download} aria-label="导出全部素材" title="导出全部素材" onClick={() => void exportAllAssets()} />
|
||||
<Button aria-label="导出全部素材" title="导出全部素材" icon={<Download className="size-3.5" />} onClick={() => void exportAllAssets()} />
|
||||
<Dropdown
|
||||
trigger={["click"]}
|
||||
menu={{
|
||||
@@ -570,7 +569,7 @@ export default function AssetsPage() {
|
||||
],
|
||||
}}
|
||||
>
|
||||
<IconButton variant="solid" icon={FileUp} aria-label="导入素材" title="导入素材" />
|
||||
<Button aria-label="导入素材" title="导入素材" icon={<FileUp className="size-3.5" />} />
|
||||
</Dropdown>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -613,7 +613,7 @@ export default function ProjectChaptersView({ detail, refreshProject }: ProjectD
|
||||
</section>
|
||||
<CreateChapterModal open={createOpen} onClose={() => setCreateOpen(false)} loading={createMutation.isPending} onSubmit={(values) => createMutation.mutate(values)} />
|
||||
<ImportNovelModal open={importOpen} loading={importMutation.isPending} onClose={() => setImportOpen(false)} onImport={(chapters) => importMutation.mutate(chapters)} />
|
||||
<Modal title="提取章节角色、场景与道具" open={characterExtractOpen} width={500} okText="开始提取" cancelText="取消" okButtonProps={{ disabled: !selectedTextModel }} onCancel={() => setCharacterExtractOpen(false)} onOk={() => void extractCharacters()} styles={{ body: { paddingTop: 12 } }}>
|
||||
<Modal className="library-modal" title="提取章节角色、场景与道具" open={characterExtractOpen} width={500} okText="开始提取" cancelText="取消" okButtonProps={{ disabled: !selectedTextModel }} onCancel={() => setCharacterExtractOpen(false)} onOk={() => void extractCharacters()} styles={{ body: { paddingTop: 12 } }}>
|
||||
<div className="grid gap-4">
|
||||
<div className="rounded-lg border border-border/70 bg-foreground/[.018] px-3 py-2.5">
|
||||
<div className="text-[var(--fs-tiny)] text-foreground/42">当前章节</div>
|
||||
@@ -626,7 +626,7 @@ export default function ProjectChaptersView({ detail, refreshProject }: ProjectD
|
||||
</label>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal title="生成章节分镜" open={storyboardOpen} width={560} okText={storyboardImpact.shotCount ? "重新生成分镜" : "生成分镜"} cancelText="取消" okButtonProps={{ disabled: !selectedTextModel }} onCancel={() => setStoryboardOpen(false)} onOk={() => void createStoryboard()} styles={{ body: { paddingTop: 12 } }}>
|
||||
<Modal className="library-modal" title="生成章节分镜" open={storyboardOpen} width={560} okText={storyboardImpact.shotCount ? "重新生成分镜" : "生成分镜"} cancelText="取消" okButtonProps={{ disabled: !selectedTextModel }} onCancel={() => setStoryboardOpen(false)} onOk={() => void createStoryboard()} styles={{ body: { paddingTop: 12 } }}>
|
||||
<div className="grid gap-4">
|
||||
<div className="rounded-lg border border-border/70 bg-foreground/[.018] px-3 py-2.5">
|
||||
<div className="text-[var(--fs-tiny)] text-foreground/42">当前章节</div>
|
||||
@@ -647,7 +647,7 @@ export default function ProjectChaptersView({ detail, refreshProject }: ProjectD
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal title="移动章节" open={Boolean(moveTargetId)} width={400} okText="移动" cancelText="取消" okButtonProps={{ disabled: !movePosition || movePosition < 1 || movePosition > orderedUnits.length, loading: reorderMutation.isPending }} onCancel={() => { setMoveTargetId(""); setMovePosition(null); }} onOk={moveChapterToPosition} styles={{ body: { paddingTop: 12 } }}>
|
||||
<Modal className="library-modal" title="移动章节" open={Boolean(moveTargetId)} width={400} okText="移动" cancelText="取消" okButtonProps={{ disabled: !movePosition || movePosition < 1 || movePosition > orderedUnits.length, loading: reorderMutation.isPending }} onCancel={() => { setMoveTargetId(""); setMovePosition(null); }} onOk={moveChapterToPosition} styles={{ body: { paddingTop: 12 } }}>
|
||||
<div className="text-xs leading-5 text-foreground/50">输入目标章节位置。适合上千章项目的长距离调整,移动后其他章节会自动顺延。</div>
|
||||
<label className="mt-3 flex items-center gap-2 text-sm"><span className="shrink-0">移动到第</span><InputNumber min={1} max={orderedUnits.length} precision={0} value={movePosition} onChange={setMovePosition} className="min-w-0 flex-1" /><span className="shrink-0">章</span></label>
|
||||
</Modal>
|
||||
@@ -736,7 +736,7 @@ function ToolbarDivider() {
|
||||
}
|
||||
|
||||
function CreateChapterModal({ open, onClose, loading, onSubmit }: { open: boolean; onClose: () => void; loading: boolean; onSubmit: (values: { title: string; sourceText?: string }) => void }) {
|
||||
return <Modal title="添加章节" open={open} footer={null} destroyOnHidden onCancel={onClose} width={480} styles={{ body: { paddingTop: 12 } }}><Form layout="vertical" onFinish={onSubmit}><Form.Item name="title" label="章节标题" rules={[{ required: true, whitespace: true, message: "请输入章节标题" }]}><Input autoFocus placeholder="例如:雨夜归城" /></Form.Item><Form.Item name="sourceText" label="正文(可选)"><Input.TextArea rows={4} placeholder="创建后仍可继续编辑和排版" /></Form.Item><div className="flex justify-end gap-2"><Button onClick={onClose}>取消</Button><Button type="primary" htmlType="submit" loading={loading}>创建章节</Button></div></Form></Modal>;
|
||||
return <Modal className="library-modal" title="添加章节" open={open} footer={null} destroyOnHidden onCancel={onClose} width={480} styles={{ body: { paddingTop: 12 } }}><Form layout="vertical" onFinish={onSubmit}><Form.Item name="title" label="章节标题" rules={[{ required: true, whitespace: true, message: "请输入章节标题" }]}><Input autoFocus placeholder="例如:雨夜归城" /></Form.Item><Form.Item name="sourceText" label="正文(可选)"><Input.TextArea rows={4} placeholder="创建后仍可继续编辑和排版" /></Form.Item><div className="flex justify-end gap-2"><Button onClick={onClose}>取消</Button><Button type="primary" htmlType="submit" loading={loading}>创建章节</Button></div></Form></Modal>;
|
||||
}
|
||||
|
||||
function ImportNovelModal({ open, loading, onClose, onImport }: { open: boolean; loading: boolean; onClose: () => void; onImport: (chapters: Array<{ title: string; plainText: string }>) => void }) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { App, Button, Input, InputNumber } from "antd";
|
||||
import { Select } from "@/components/ui/base/select";
|
||||
import { SettingsRow } from "@/components/ui/product/settings-row";
|
||||
import { ArrowLeft, Boxes, Bug, Cloud, MessageSquareText, MonitorUp, RadioTower, SlidersHorizontal, SquareTerminal, Workflow } from "lucide-react";
|
||||
import { useEffect, useMemo, useState, type ReactNode } from "react";
|
||||
import { useEffect, useLayoutEffect, useMemo, useState, type ReactNode } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router";
|
||||
|
||||
import { UserOSSSettingsForm } from "@/components/layout/user-oss-settings-form";
|
||||
@@ -65,6 +65,11 @@ export default function SettingsPage() {
|
||||
|
||||
const isVisibleConfigSection = (value: string | null): value is ConfigSectionKey => isConfigSection(value) && visibleConfigSections.some((section) => section.key === value);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
document.body.classList.add("app-user-overlays");
|
||||
return () => document.body.classList.remove("app-user-overlays");
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisibleConfigSection(requestedSection)) {
|
||||
setActiveTab(requestedSection);
|
||||
@@ -212,7 +217,7 @@ export default function SettingsPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="settings-page app-workspace-page flex h-full min-h-0 flex-col text-foreground">
|
||||
<main className="settings-page app-workspace-page app-user-workspace flex h-full min-h-0 flex-col text-foreground">
|
||||
<header className="settings-topbar shrink-0">
|
||||
<div className="flex min-w-0 items-center gap-2.5">
|
||||
{shouldPromptContinue ? (
|
||||
|
||||
Reference in New Issue
Block a user