feat: 部分二次确认弹框样式调整
This commit is contained in:
@@ -15,20 +15,31 @@ export default function ConfirmModal({
|
|||||||
onConfirm,
|
onConfirm,
|
||||||
onCancel,
|
onCancel,
|
||||||
confirmText = '确定删除',
|
confirmText = '确定删除',
|
||||||
|
icon,
|
||||||
|
confirmVariant = 'danger', // 'danger' | 'primary' | 'secondary'
|
||||||
}) {
|
}) {
|
||||||
const handleOpenChange = (open) => {
|
const handleOpenChange = (open) => {
|
||||||
if (!open) onCancel();
|
if (!open) onCancel();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const confirmButtonToneClass =
|
||||||
|
confirmVariant === 'primary'
|
||||||
|
? 'button'
|
||||||
|
: confirmVariant === 'secondary'
|
||||||
|
? 'button secondary'
|
||||||
|
: 'button danger';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open onOpenChange={handleOpenChange}>
|
<Dialog open onOpenChange={handleOpenChange}>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
overlayClassName="!z-[1200]"
|
overlayClassName="!z-[12000]"
|
||||||
showCloseButton={false}
|
showCloseButton={false}
|
||||||
className="!z-[1210] max-w-[400px] flex flex-col gap-5 p-6"
|
className="!z-[12010] max-w-[400px] flex flex-col gap-5 p-6"
|
||||||
>
|
>
|
||||||
<DialogHeader className="flex flex-row items-center gap-3 text-left">
|
<DialogHeader className="flex flex-row items-center gap-3 text-left">
|
||||||
<TrashIcon width="20" height="20" className="shrink-0 text-[var(--danger)]" />
|
{icon || (
|
||||||
|
<TrashIcon width="20" height="20" className="shrink-0 text-[var(--danger)]" />
|
||||||
|
)}
|
||||||
<DialogTitle className="flex-1 text-base font-semibold">{title}</DialogTitle>
|
<DialogTitle className="flex-1 text-base font-semibold">{title}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogDescription className="text-left text-sm leading-relaxed text-[var(--muted-foreground)]">
|
<DialogDescription className="text-left text-sm leading-relaxed text-[var(--muted-foreground)]">
|
||||||
@@ -44,7 +55,7 @@ export default function ConfirmModal({
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="button danger min-w-0 flex-1 cursor-pointer h-auto min-h-[48px] py-3 sm:h-11 sm:min-h-0 sm:py-0"
|
className={`${confirmButtonToneClass} min-w-0 flex-1 cursor-pointer h-auto min-h-[48px] py-3 sm:h-11 sm:min-h-0 sm:py-0`}
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
>
|
>
|
||||||
{confirmText}
|
{confirmText}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { CloseIcon, DragIcon, ExitIcon, SettingsIcon, StarIcon, TrashIcon } from './Icons';
|
import { CloseIcon, DragIcon, ExitIcon, SettingsIcon, StarIcon, TrashIcon, ResetIcon } from './Icons';
|
||||||
|
|
||||||
const NON_FROZEN_COLUMN_IDS = [
|
const NON_FROZEN_COLUMN_IDS = [
|
||||||
'yesterdayChangePercent',
|
'yesterdayChangePercent',
|
||||||
@@ -1117,6 +1117,8 @@ export default function PcFundTable({
|
|||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
title="重置列宽"
|
title="重置列宽"
|
||||||
message="是否重置表格列宽为默认值?"
|
message="是否重置表格列宽为默认值?"
|
||||||
|
icon={<ResetIcon width="20" height="20" className="shrink-0 text-[var(--primary)]" />}
|
||||||
|
confirmVariant="primary"
|
||||||
onConfirm={handleResetSizing}
|
onConfirm={handleResetSizing}
|
||||||
onCancel={() => setResetConfirmOpen(false)}
|
onCancel={() => setResetConfirmOpen(false)}
|
||||||
confirmText="重置"
|
confirmText="重置"
|
||||||
|
|||||||
@@ -267,6 +267,8 @@ export default function PcTableSettingModal({
|
|||||||
key="reset-order-confirm"
|
key="reset-order-confirm"
|
||||||
title="重置表头设置"
|
title="重置表头设置"
|
||||||
message="是否重置表头顺序和显示/隐藏为默认值?"
|
message="是否重置表头顺序和显示/隐藏为默认值?"
|
||||||
|
icon={<ResetIcon width="20" height="20" className="shrink-0 text-[var(--primary)]" />}
|
||||||
|
confirmVariant="primary"
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
onResetColumnOrder?.();
|
onResetColumnOrder?.();
|
||||||
onResetColumnVisibility?.();
|
onResetColumnVisibility?.();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
|
||||||
|
import { Progress } from '@/components/ui/progress';
|
||||||
import ConfirmModal from './ConfirmModal';
|
import ConfirmModal from './ConfirmModal';
|
||||||
import { ResetIcon, SettingsIcon } from './Icons';
|
import { ResetIcon, SettingsIcon } from './Icons';
|
||||||
|
|
||||||
@@ -22,6 +23,21 @@ export default function SettingsModal({
|
|||||||
const [sliderDragging, setSliderDragging] = useState(false);
|
const [sliderDragging, setSliderDragging] = useState(false);
|
||||||
const [resetWidthConfirmOpen, setResetWidthConfirmOpen] = useState(false);
|
const [resetWidthConfirmOpen, setResetWidthConfirmOpen] = useState(false);
|
||||||
const [localSeconds, setLocalSeconds] = useState(tempSeconds);
|
const [localSeconds, setLocalSeconds] = useState(tempSeconds);
|
||||||
|
const pageWidthTrackRef = useRef(null);
|
||||||
|
|
||||||
|
const clampedWidth = Math.min(2000, Math.max(600, Number(containerWidth) || 1200));
|
||||||
|
const pageWidthPercent = ((clampedWidth - 600) / (2000 - 600)) * 100;
|
||||||
|
|
||||||
|
const updateWidthByClientX = (clientX) => {
|
||||||
|
if (!pageWidthTrackRef.current || !setContainerWidth) return;
|
||||||
|
const rect = pageWidthTrackRef.current.getBoundingClientRect();
|
||||||
|
if (!rect.width) return;
|
||||||
|
const ratio = (clientX - rect.left) / rect.width;
|
||||||
|
const clampedRatio = Math.min(1, Math.max(0, ratio));
|
||||||
|
const rawWidth = 600 + clampedRatio * (2000 - 600);
|
||||||
|
const snapped = Math.round(rawWidth / 10) * 10;
|
||||||
|
setContainerWidth(snapped);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!sliderDragging) return;
|
if (!sliderDragging) return;
|
||||||
@@ -115,23 +131,32 @@ export default function SettingsModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
<input
|
<div
|
||||||
type="range"
|
ref={pageWidthTrackRef}
|
||||||
min={600}
|
className="group relative"
|
||||||
max={2000}
|
style={{ flex: 1, height: 14, cursor: 'pointer', display: 'flex', alignItems: 'center' }}
|
||||||
step={10}
|
onPointerDown={(e) => {
|
||||||
value={Math.min(2000, Math.max(600, Number(containerWidth) || 1200))}
|
setSliderDragging(true);
|
||||||
onChange={(e) => setContainerWidth(Number(e.target.value))}
|
updateWidthByClientX(e.clientX);
|
||||||
onPointerDown={() => setSliderDragging(true)}
|
e.currentTarget.setPointerCapture?.(e.pointerId);
|
||||||
className="page-width-slider"
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
height: 6,
|
|
||||||
accentColor: 'var(--primary)',
|
|
||||||
}}
|
}}
|
||||||
/>
|
onPointerMove={(e) => {
|
||||||
|
if (!sliderDragging) return;
|
||||||
|
updateWidthByClientX(e.clientX);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Progress value={pageWidthPercent} />
|
||||||
|
<div
|
||||||
|
className="pointer-events-none absolute top-1/2 -translate-y-1/2"
|
||||||
|
style={{ left: `${pageWidthPercent}%`, transform: 'translate(-50%, -50%)' }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="h-3 w-3 rounded-full bg-primary shadow-md shadow-primary/40"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<span className="muted" style={{ fontSize: '0.8rem', minWidth: 48 }}>
|
<span className="muted" style={{ fontSize: '0.8rem', minWidth: 48 }}>
|
||||||
{Math.min(2000, Math.max(600, Number(containerWidth) || 1200))}px
|
{clampedWidth}px
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,6 +200,8 @@ export default function SettingsModal({
|
|||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
title="重置页面宽度"
|
title="重置页面宽度"
|
||||||
message="是否重置页面宽度为默认值 1200px?"
|
message="是否重置页面宽度为默认值 1200px?"
|
||||||
|
icon={<ResetIcon width="20" height="20" className="shrink-0 text-[var(--primary)]" />}
|
||||||
|
confirmVariant="primary"
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
onResetContainerWidth();
|
onResetContainerWidth();
|
||||||
setResetWidthConfirmOpen(false);
|
setResetWidthConfirmOpen(false);
|
||||||
|
|||||||
43
components/ui/progress.jsx
Normal file
43
components/ui/progress.jsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import { Progress as ProgressPrimitive } from "radix-ui"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Progress({
|
||||||
|
className,
|
||||||
|
value,
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<ProgressPrimitive.Root
|
||||||
|
data-slot="progress"
|
||||||
|
className={cn(
|
||||||
|
// 细高条,轻玻璃质感,统一用 CSS 变量
|
||||||
|
"relative w-full overflow-hidden rounded-full",
|
||||||
|
"h-1.5 sm:h-1.5",
|
||||||
|
"bg-[var(--input)]/70 dark:bg-[var(--input)]/40",
|
||||||
|
"border border-[var(--border)]/80 dark:border-[var(--border)]/80",
|
||||||
|
"shadow-[0_0_0_1px_rgba(15,23,42,0.02)] dark:shadow-[0_0_0_1px_rgba(15,23,42,0.6)]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}>
|
||||||
|
<ProgressPrimitive.Indicator
|
||||||
|
data-slot="progress-indicator"
|
||||||
|
className={cn(
|
||||||
|
"h-full w-full flex-1",
|
||||||
|
// 金融风轻渐变,兼容明暗主题
|
||||||
|
"bg-gradient-to-r from-[var(--primary)] to-[var(--primary)]/80",
|
||||||
|
"dark:from-[var(--primary)] dark:to-[var(--secondary)]/90",
|
||||||
|
// 柔和发光,不喧宾夺主
|
||||||
|
"shadow-[0_0_8px_rgba(245,158,11,0.35)] dark:shadow-[0_0_14px_rgba(245,158,11,0.45)]",
|
||||||
|
// 平滑进度动画
|
||||||
|
"transition-[transform,box-shadow] duration-250 ease-out"
|
||||||
|
)}
|
||||||
|
style={{ transform: `translateX(-${100 - (value || 0)}%)` }} />
|
||||||
|
</ProgressPrimitive.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Progress }
|
||||||
Reference in New Issue
Block a user