style: fix prettier formatting issues
Deploy / Build Production Runtime Images (push) Has been skipped
Deploy / Deploy Production (push) Has been skipped
Deploy / Production Browser E2E (push) Has been skipped
Deploy / Deploy Staging (push) Failing after 192h26m58s
CI/CD Pipeline / Frontend Lint (push) Failing after 192h27m37s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 192h27m46s
Deploy / Build Production Runtime Images (push) Has been skipped
Deploy / Deploy Production (push) Has been skipped
Deploy / Production Browser E2E (push) Has been skipped
Deploy / Deploy Staging (push) Failing after 192h26m58s
CI/CD Pipeline / Frontend Lint (push) Failing after 192h27m37s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 192h27m46s
This commit is contained in:
@@ -145,7 +145,8 @@
|
||||
|
||||
.xx-search-input:focus {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary-color) 10%, transparent);
|
||||
box-shadow: 0 0 0 4px
|
||||
color-mix(in srgb, var(--primary-color) 10%, transparent);
|
||||
}
|
||||
|
||||
/* ==================== Modal ==================== */
|
||||
@@ -221,7 +222,8 @@
|
||||
|
||||
.xx-quota-item:hover {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 8px 24px color-mix(in srgb, var(--primary-color) 10%, transparent);
|
||||
box-shadow: 0 8px 24px
|
||||
color-mix(in srgb, var(--primary-color) 10%, transparent);
|
||||
}
|
||||
|
||||
/* ==================== 进度条 ==================== */
|
||||
@@ -331,7 +333,8 @@
|
||||
|
||||
.ant-select-focused .ant-select-selector {
|
||||
border-color: var(--primary-color) !important;
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 10%, transparent) !important;
|
||||
box-shadow: 0 0 0 3px
|
||||
color-mix(in srgb, var(--primary-color) 10%, transparent) !important;
|
||||
}
|
||||
|
||||
/* Input overrides */
|
||||
@@ -347,7 +350,8 @@
|
||||
|
||||
.ant-input:focus {
|
||||
border-color: var(--primary-color) !important;
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 10%, transparent) !important;
|
||||
box-shadow: 0 0 0 3px
|
||||
color-mix(in srgb, var(--primary-color) 10%, transparent) !important;
|
||||
}
|
||||
|
||||
/* Progress overrides */
|
||||
|
||||
@@ -17,8 +17,6 @@ import type { MenuProps } from "antd";
|
||||
import { NAV_ITEMS } from "@/config/navigation";
|
||||
import "./Header.css";
|
||||
|
||||
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
@@ -142,7 +142,6 @@
|
||||
.xx-app-sidebar:not(.xx-collapsed) .xx-sidebar-toggle-label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
|
||||
@@ -138,7 +138,10 @@ const PageHead: React.FC<PageHeadProps> = ({
|
||||
{breadcrumbItems.map((item, index) => {
|
||||
const isLast = index === breadcrumbItems.length - 1;
|
||||
return (
|
||||
<li key={`${item.label}-${index}`} className="xx-page-breadcrumb-item">
|
||||
<li
|
||||
key={`${item.label}-${index}`}
|
||||
className="xx-page-breadcrumb-item"
|
||||
>
|
||||
{index > 0 && (
|
||||
<RightOutlined className="xx-page-breadcrumb-separator" />
|
||||
)}
|
||||
@@ -157,7 +160,10 @@ const PageHead: React.FC<PageHeadProps> = ({
|
||||
<span>{item.label}</span>
|
||||
</Link>
|
||||
) : (
|
||||
<span className="xx-page-breadcrumb-current" aria-current="page">
|
||||
<span
|
||||
className="xx-page-breadcrumb-current"
|
||||
aria-current="page"
|
||||
>
|
||||
{index === 0 ? (
|
||||
<HomeOutlined className="xx-page-breadcrumb-home" />
|
||||
) : null}
|
||||
|
||||
@@ -33,7 +33,9 @@ const Sidebar: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`xx-sidebar-nav${collapsed ? " xx-sidebar-nav--collapsed" : ""}`}>
|
||||
<div
|
||||
className={`xx-sidebar-nav${collapsed ? " xx-sidebar-nav--collapsed" : ""}`}
|
||||
>
|
||||
{NAV_GROUPS.map((group) => (
|
||||
<div className="xx-sidebar-group" key={group.title}>
|
||||
{!collapsed && (
|
||||
|
||||
@@ -124,7 +124,9 @@ const CloneVoiceModal: React.FC<CloneVoiceModalProps> = ({
|
||||
// Mock:模拟上传 + 克隆过程
|
||||
const result = await createVoiceClone({
|
||||
name,
|
||||
audio_url: selectedFile ? `mock://${selectedFile.name}` : "mock://recorded-audio",
|
||||
audio_url: selectedFile
|
||||
? `mock://${selectedFile.name}`
|
||||
: "mock://recorded-audio",
|
||||
});
|
||||
|
||||
setStep("success");
|
||||
@@ -211,7 +213,9 @@ const CloneVoiceModal: React.FC<CloneVoiceModalProps> = ({
|
||||
<label className="cvm-label">直接录制</label>
|
||||
<div className="cvm-record-area">
|
||||
<p className="cvm-record-hint">
|
||||
{isRecording ? "录制中…再次点击停止" : "点击按钮开始录制你的声音"}
|
||||
{isRecording
|
||||
? "录制中…再次点击停止"
|
||||
: "点击按钮开始录制你的声音"}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
@@ -226,7 +230,9 @@ const CloneVoiceModal: React.FC<CloneVoiceModalProps> = ({
|
||||
{/* 提示 */}
|
||||
<div className="cvm-tip">
|
||||
<span className="cvm-tip-icon">💡</span>
|
||||
<span>建议上传10秒~3分钟的清晰语音,环境安静、语速均匀效果最佳</span>
|
||||
<span>
|
||||
建议上传10秒~3分钟的清晰语音,环境安静、语速均匀效果最佳
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 底部按钮 */}
|
||||
@@ -234,7 +240,11 @@ const CloneVoiceModal: React.FC<CloneVoiceModalProps> = ({
|
||||
<Button buttonType="ghost" onClick={handleClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button buttonType="primary" disabled={!canStart} onClick={handleStartClone}>
|
||||
<Button
|
||||
buttonType="primary"
|
||||
disabled={!canStart}
|
||||
onClick={handleStartClone}
|
||||
>
|
||||
🎤 开始克隆
|
||||
</Button>
|
||||
</div>
|
||||
@@ -255,7 +265,9 @@ const CloneVoiceModal: React.FC<CloneVoiceModalProps> = ({
|
||||
<div className="cvm-success">
|
||||
<div className="cvm-success-icon">✅</div>
|
||||
<h3 className="cvm-success-title">克隆已提交</h3>
|
||||
<p className="cvm-success-desc">音色正在生成中,完成后将出现在列表中</p>
|
||||
<p className="cvm-success-desc">
|
||||
音色正在生成中,完成后将出现在列表中
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
@@ -36,13 +36,16 @@
|
||||
color: var(--text-primary, #101828);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cvm-input:focus {
|
||||
border-color: var(--primary, #6366f1);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 12%, transparent);
|
||||
box-shadow: 0 0 0 3px
|
||||
color-mix(in srgb, var(--primary-color) 12%, transparent);
|
||||
}
|
||||
|
||||
.cvm-input::placeholder {
|
||||
@@ -58,7 +61,9 @@
|
||||
text-align: center;
|
||||
background: var(--bg-subtle, #f8fafc);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, background 0.2s;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
background 0.2s;
|
||||
}
|
||||
|
||||
.cvm-upload-zone:hover {
|
||||
@@ -135,10 +140,17 @@
|
||||
font-size: 32px;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
background: linear-gradient(135deg, var(--error-color, #ef4444), var(--error-dark, #dc2626));
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
var(--error-color, #ef4444),
|
||||
var(--error-dark, #dc2626)
|
||||
);
|
||||
color: var(--text-inverse);
|
||||
box-shadow: 0 4px 14px color-mix(in srgb, var(--error-color, #ef4444) 35%, transparent);
|
||||
transition: transform 0.15s, box-shadow 0.15s;
|
||||
box-shadow: 0 4px 14px
|
||||
color-mix(in srgb, var(--error-color, #ef4444) 35%, transparent);
|
||||
transition:
|
||||
transform 0.15s,
|
||||
box-shadow 0.15s;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -146,7 +158,8 @@
|
||||
|
||||
.cvm-record-btn:hover {
|
||||
transform: scale(1.06);
|
||||
box-shadow: 0 6px 20px color-mix(in srgb, var(--error-color, #ef4444) 45%, transparent);
|
||||
box-shadow: 0 6px 20px
|
||||
color-mix(in srgb, var(--error-color, #ef4444) 45%, transparent);
|
||||
}
|
||||
|
||||
.cvm-record-btn:active {
|
||||
@@ -158,8 +171,15 @@
|
||||
}
|
||||
|
||||
@keyframes cvm-pulse {
|
||||
0%, 100% { box-shadow: 0 4px 14px color-mix(in srgb, var(--error-color, #ef4444) 35%, transparent); }
|
||||
50% { box-shadow: 0 4px 28px color-mix(in srgb, var(--error-color, #ef4444) 60%, transparent); }
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0 4px 14px
|
||||
color-mix(in srgb, var(--error-color, #ef4444) 35%, transparent);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 4px 28px
|
||||
color-mix(in srgb, var(--error-color, #ef4444) 60%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 提示条 ─────────────────────────────────────────────── */
|
||||
@@ -215,7 +235,9 @@
|
||||
}
|
||||
|
||||
@keyframes cvm-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.cvm-uploading-text {
|
||||
@@ -262,7 +284,6 @@
|
||||
|
||||
/* ── 响应式 ─────────────────────────────────────────────── */
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cvm-overlay {
|
||||
padding: var(--space-md);
|
||||
|
||||
@@ -9,12 +9,7 @@ import classNames from "classnames";
|
||||
import "./ui.css";
|
||||
|
||||
export type ButtonType =
|
||||
| "primary"
|
||||
| "secondary"
|
||||
| "ghost"
|
||||
| "text"
|
||||
| "danger"
|
||||
| "link";
|
||||
"primary" | "secondary" | "ghost" | "text" | "danger" | "link";
|
||||
|
||||
export type ButtonSize = "sm" | "md" | "lg";
|
||||
|
||||
@@ -70,7 +65,9 @@ const Button: React.FC<ButtonProps> = ({
|
||||
...rest
|
||||
}) => {
|
||||
const antdType = type ?? toAntdType(buttonType);
|
||||
const antdSize = size ?? (buttonSize === "sm" ? "small" : buttonSize === "lg" ? "large" : "middle");
|
||||
const antdSize =
|
||||
size ??
|
||||
(buttonSize === "sm" ? "small" : buttonSize === "lg" ? "large" : "middle");
|
||||
|
||||
const v21Class = classNames(
|
||||
"xx-btn",
|
||||
|
||||
@@ -20,7 +20,10 @@ const Form = ({ className, compact, children, ...rest }: FormProps) => {
|
||||
className,
|
||||
);
|
||||
return (
|
||||
<AntForm className={v21Class} {...(rest as Omit<FormProps, "className" | "compact" | "children">)}>
|
||||
<AntForm
|
||||
className={v21Class}
|
||||
{...(rest as Omit<FormProps, "className" | "compact" | "children">)}
|
||||
>
|
||||
{children as React.ReactNode}
|
||||
</AntForm>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,11 @@ import type { InputRef } from "antd/es/input";
|
||||
import classNames from "classnames";
|
||||
import "./ui.css";
|
||||
|
||||
const { Search: AntSearch, TextArea: AntTextArea, Password: AntPassword } = AntInput;
|
||||
const {
|
||||
Search: AntSearch,
|
||||
TextArea: AntTextArea,
|
||||
Password: AntPassword,
|
||||
} = AntInput;
|
||||
|
||||
export interface InputProps extends AntInputProps {
|
||||
/** 是否处于错误状态 */
|
||||
@@ -46,11 +50,7 @@ const Search: React.FC<
|
||||
const TextArea: React.FC<
|
||||
React.ComponentProps<typeof AntTextArea> & { error?: boolean }
|
||||
> = ({ className, error, ...rest }) => {
|
||||
const v21Class = classNames(
|
||||
"xx-input",
|
||||
error && "xx-input-error",
|
||||
className,
|
||||
);
|
||||
const v21Class = classNames("xx-input", error && "xx-input-error", className);
|
||||
return <AntTextArea className={v21Class} {...rest} />;
|
||||
};
|
||||
|
||||
@@ -59,11 +59,7 @@ const Password = React.forwardRef<
|
||||
InputRef,
|
||||
React.ComponentProps<typeof AntPassword> & { error?: boolean }
|
||||
>(({ className, error, ...rest }, ref) => {
|
||||
const v21Class = classNames(
|
||||
"xx-input",
|
||||
error && "xx-input-error",
|
||||
className,
|
||||
);
|
||||
const v21Class = classNames("xx-input", error && "xx-input-error", className);
|
||||
return <AntPassword ref={ref} className={v21Class} {...rest} />;
|
||||
});
|
||||
Password.displayName = "Password";
|
||||
|
||||
@@ -19,10 +19,7 @@ const Select: React.FC<SelectProps> = ({
|
||||
...rest
|
||||
}) => {
|
||||
const v21Class = classNames("xx-select", className);
|
||||
const v21DropdownClass = classNames(
|
||||
"xx-select-dropdown",
|
||||
dropdownClassName,
|
||||
);
|
||||
const v21DropdownClass = classNames("xx-select-dropdown", dropdownClassName);
|
||||
return (
|
||||
<AntSelect
|
||||
className={v21Class}
|
||||
|
||||
@@ -8,8 +8,9 @@ import type { TableProps as AntTableProps } from "antd";
|
||||
import classNames from "classnames";
|
||||
import "./ui.css";
|
||||
|
||||
export interface TableProps<RecordType = unknown>
|
||||
extends AntTableProps<RecordType> {
|
||||
export interface TableProps<
|
||||
RecordType = unknown,
|
||||
> extends AntTableProps<RecordType> {
|
||||
/** 使用 V21 样式 */
|
||||
v21?: boolean;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
*/
|
||||
import React from "react";
|
||||
import { Tag as AntTag, Badge as AntBadge } from "antd";
|
||||
import type { TagProps as AntTagProps, BadgeProps as AntBadgeProps } from "antd";
|
||||
import type {
|
||||
TagProps as AntTagProps,
|
||||
BadgeProps as AntBadgeProps,
|
||||
} from "antd";
|
||||
import classNames from "classnames";
|
||||
import "./ui.css";
|
||||
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
* 封装 Ant Design Tooltip 和 Popover,应用 V21 设计系统样式
|
||||
*/
|
||||
import React from "react";
|
||||
import {
|
||||
Tooltip as AntTooltip,
|
||||
Popover as AntPopover,
|
||||
} from "antd";
|
||||
import { Tooltip as AntTooltip, Popover as AntPopover } from "antd";
|
||||
import classNames from "classnames";
|
||||
import "./ui.css";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user