样式修改

This commit is contained in:
董宏凯 committed 2026-05-20 15:21:23 +08:00
1 parent c2c44f8d29
commit 03dff2ce77
17 files changed
+577 -58

No files matched your search

@@ -0,0 +1,34 @@
import type { ReactNode } from 'react';
import { cn } from '@/lib/utils';
interface CollapseTransitionProps {
open: boolean;
className?: string;
innerClassName?: string;
duration?: number;
children: ReactNode;
}
export function CollapseTransition({
open,
className,
innerClassName,
duration = 200,
children,
}: CollapseTransitionProps) {
return (
<div
aria-hidden={!open}
style={{ transitionDuration: `${duration}ms` }}
className={cn(
'grid overflow-hidden transition-[grid-template-rows,opacity] ease-out',
open ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none',
className,
)}
>
<div className={cn('min-h-0 overflow-hidden', innerClassName)}>
{children}
</div>
</div>
);
}
@@ -1,6 +1,6 @@
import { useState } from 'react';
import {
CheckCircle2, ChevronRight, ChevronDown,
CheckCircle2, ChevronRight,
ExternalLink, ListTree, FileText,
} from 'lucide-react';
import { cn } from '@/lib/utils';
@@ -9,6 +9,7 @@ import type { AIMaterial, CompletedIntervention } from '../../types/ai-writing';
import { OutlineCard } from './OutlineCard';
import { ReviewCard } from './ReviewCard';
import { ScoreBar } from './ScoreBar';
import { CollapseTransition } from './CollapseTransition';
interface Props {
record: CompletedIntervention;
@@ -57,19 +58,22 @@ function MaterialCompleted({ record, expanded, onToggle }: { record: CompletedIn
)}
</span>
{count > 0 && (
expanded
? <ChevronDown className="size-3 text-muted-foreground" />
: <ChevronRight className="size-3 text-muted-foreground" />
<ChevronRight
className={cn(
'size-3 text-muted-foreground transition-transform duration-200',
expanded && 'rotate-90',
)}
/>
)}
</button>
{expanded && record.materials && record.materials.length > 0 && (
<div className="px-2.5 pb-2.5 pt-1 space-y-1.5 border-t border-green-200/40 dark:border-green-900/20">
{record.materials.map((m) => (
<CollapseTransition open={expanded && !!record.materials && record.materials.length > 0}>
<div className="px-2.5 pb-2.5 pt-1.5 space-y-1.5 border-t border-green-200/40 dark:border-green-900/20">
{record.materials?.map((m) => (
<CompletedMaterialItem key={m.id} material={m} />
))}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -102,9 +106,12 @@ function CompletedMaterialItem({ material }: { material: AIMaterial }) {
<div className="flex items-start gap-1.5">
<span className="flex-1 font-medium leading-snug line-clamp-2">{material.title}</span>
{hasDetail && (
open
? <ChevronDown className="mt-0.5 size-3 shrink-0 text-muted-foreground" />
: <ChevronRight className="mt-0.5 size-3 shrink-0 text-muted-foreground" />
<ChevronRight
className={cn(
'mt-0.5 size-3 shrink-0 text-muted-foreground transition-transform duration-200',
open && 'rotate-90',
)}
/>
)}
</div>
<div className="flex items-center gap-2 text-muted-foreground">
@@ -120,7 +127,7 @@ function CompletedMaterialItem({ material }: { material: AIMaterial }) {
</div>
</button>
{open && hasDetail && (
<CollapseTransition open={open && hasDetail}>
<div className="px-2.5 pb-2 pt-1.5 space-y-1.5 border-t border-border/40">
{material.content && (
<p className="text-muted-foreground leading-relaxed line-clamp-6">
@@ -139,7 +146,7 @@ function CompletedMaterialItem({ material }: { material: AIMaterial }) {
</button>
)}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -168,17 +175,20 @@ function OutlineCompleted({ record, expanded, onToggle }: { record: CompletedInt
<span className="ml-1 text-muted-foreground font-normal">共 {sectionCount} 章节</span>
</span>
{record.outline && (
expanded
? <ChevronDown className="size-3 text-muted-foreground" />
: <ChevronRight className="size-3 text-muted-foreground" />
<ChevronRight
className={cn(
'size-3 text-muted-foreground transition-transform duration-200',
expanded && 'rotate-90',
)}
/>
)}
</button>
{expanded && record.outline && (
<CollapseTransition open={expanded && !!record.outline}>
<div className="px-2.5 pb-2.5 pt-1 border-t border-green-200/40 dark:border-green-900/20">
<OutlineCard outline={record.outline} readOnly />
{record.outline && <OutlineCard outline={record.outline} readOnly />}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -217,17 +227,20 @@ function DraftCompleted({ record, expanded, onToggle }: { record: CompletedInter
{wordCount > 0 && <span className="ml-1">({wordCount} 字)</span>}
</span>
{hasReview && (
expanded
? <ChevronDown className="size-3 text-muted-foreground" />
: <ChevronRight className="size-3 text-muted-foreground" />
<ChevronRight
className={cn(
'size-3 text-muted-foreground transition-transform duration-200',
expanded && 'rotate-90',
)}
/>
)}
</button>
{expanded && record.reviewResult && (
<CollapseTransition open={expanded && !!record.reviewResult}>
<div className="px-2.5 pb-2.5 pt-1 border-t border-green-200/40 dark:border-green-900/20">
<ReviewCard review={record.reviewResult} />
{record.reviewResult && <ReviewCard review={record.reviewResult} />}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -259,19 +272,26 @@ function ReviewCompleted({ record, expanded, onToggle }: { record: CompletedInte
</span>
)}
{hasReview && (
expanded
? <ChevronDown className="size-3 text-muted-foreground" />
: <ChevronRight className="size-3 text-muted-foreground" />
<ChevronRight
className={cn(
'size-3 text-muted-foreground transition-transform duration-200',
expanded && 'rotate-90',
)}
/>
)}
</button>
{expanded && record.reviewResult && (
<CollapseTransition open={expanded && !!record.reviewResult}>
<div className="px-2.5 pb-2.5 pt-1 space-y-1.5 border-t border-green-200/40 dark:border-green-900/20">
<ScoreBar label="事实准确性" score={record.reviewResult.factScore} />
<ScoreBar label="逻辑结构" score={record.reviewResult.logicScore} />
<ScoreBar label="语言文字" score={record.reviewResult.languageScore} />
{record.reviewResult && (
<>
<ScoreBar label="事实准确性" score={record.reviewResult.factScore} />
<ScoreBar label="逻辑结构" score={record.reviewResult.logicScore} />
<ScoreBar label="语言文字" score={record.reviewResult.languageScore} />
</>
)}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -1,7 +1,8 @@
import { useEffect, useRef, useState } from 'react';
import { Brain, ChevronDown, ChevronRight } from 'lucide-react';
import { Brain, ChevronRight } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { StreamingDraftSection } from '../../types/ai-writing';
import { CollapseTransition } from './CollapseTransition';
interface DraftStreamingViewProps {
title: string;
@@ -40,10 +41,10 @@ function SectionThinking({ thinkingText, isDone }: { thinkingText: string; isDon
<Brain className="size-3 text-amber-500 shrink-0" />
<span className="text-[11px] font-medium text-amber-600 dark:text-amber-400">思考过程</span>
<span className="ml-auto text-amber-400">
{open ? <ChevronDown className="size-3" /> : <ChevronRight className="size-3" />}
<ChevronRight className={cn('size-3 transition-transform duration-200', open && 'rotate-90')} />
</span>
</button>
{open && (
<CollapseTransition open={open}>
<pre
ref={preRef}
className="text-[10px] font-mono leading-relaxed px-2.5 py-2 text-amber-700/70 dark:text-amber-300/60 whitespace-pre-wrap max-h-32 overflow-y-auto italic"
@@ -53,7 +54,7 @@ function SectionThinking({ thinkingText, isDone }: { thinkingText: string; isDon
<span className="inline-block w-0.5 h-3 bg-amber-400 ml-0.5 align-text-bottom animate-[blink_1s_step-end_infinite]" />
)}
</pre>
)}
</CollapseTransition>
</div>
);
}
@@ -1,8 +1,9 @@
import { useState } from 'react';
import { ChevronRight, ChevronDown, ExternalLink } from 'lucide-react';
import { ChevronRight, ExternalLink } from 'lucide-react';
import { cn } from '@/lib/utils';
import { buildIntranetSourceUrl } from '@/core/config';
import type { AIMaterial } from '../../types/ai-writing';
import { CollapseTransition } from './CollapseTransition';
interface MaterialItemProps {
material: AIMaterial;
@@ -52,9 +53,12 @@ export function MaterialItem({ material, checked, onToggle }: MaterialItemProps)
<span className={cn('flex-1 font-medium leading-snug line-clamp-2', !checked && 'text-muted-foreground')}>
{material.title}
</span>
{expanded
? <ChevronDown className="mt-0.5 size-3 shrink-0 text-muted-foreground" />
: <ChevronRight className="mt-0.5 size-3 shrink-0 text-muted-foreground" />}
<ChevronRight
className={cn(
'mt-0.5 size-3 shrink-0 text-muted-foreground transition-transform duration-200',
expanded && 'rotate-90',
)}
/>
</button>
</div>
@@ -83,7 +87,7 @@ export function MaterialItem({ material, checked, onToggle }: MaterialItemProps)
</div>
{/* 展开内容 */}
{expanded && (
<CollapseTransition open={expanded}>
<div className="px-2.5 pb-2.5 pl-8 space-y-1.5 border-t">
<p className="text-muted-foreground leading-relaxed pt-2 line-clamp-6">
{material.content.slice(0, 300)}
@@ -102,7 +106,7 @@ export function MaterialItem({ material, checked, onToggle }: MaterialItemProps)
</button>
)}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -1,7 +1,9 @@
import { useState } from 'react';
import { ChevronDown, ChevronRight, FileText } from 'lucide-react';
import { ChevronRight, FileText } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { AIMaterial } from '../../types/ai-writing';
import { MaterialItem } from './MaterialItem';
import { CollapseTransition } from './CollapseTransition';
interface MaterialsCardProps {
materials: AIMaterial[];
@@ -27,14 +29,17 @@ export function MaterialsCard({ materials, selectedIds, onToggle }: MaterialsCar
(共 {materials.length} 条,已选 {selectedIds.size} 条)
</span>
</span>
{expanded
? <ChevronDown className="size-3 text-muted-foreground" />
: <ChevronRight className="size-3 text-muted-foreground" />}
<ChevronRight
className={cn(
'size-3 text-muted-foreground transition-transform duration-200',
expanded && 'rotate-90',
)}
/>
</button>
{/* 列表 */}
{expanded && (
<div className="px-2.5 pb-2.5 space-y-1.5 border-t">
<CollapseTransition open={expanded}>
<div className="px-2.5 pb-2.5 pt-1.5 space-y-1.5 border-t">
{materials.length === 0 ? (
<p className="text-xs text-muted-foreground py-2 text-center">暂无素材</p>
) : (
@@ -48,7 +53,7 @@ export function MaterialsCard({ materials, selectedIds, onToggle }: MaterialsCar
))
)}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -3,6 +3,7 @@ import { ListTree, Plus } from 'lucide-react';
import { Button } from '@/components/ui/button';
import type { AIOutline, OutlineSection as OutlineSectionType } from '../../types/ai-writing';
import { OutlineSection } from './OutlineSection';
import { CollapseTransition } from './CollapseTransition';
interface OutlineCardProps {
outline: AIOutline;
@@ -69,7 +70,7 @@ export function OutlineCard({ outline, onChange, readOnly = false }: OutlineCard
</button>
</div>
{!collapsed && (
<CollapseTransition open={!collapsed}>
<div className="px-3 py-2.5 space-y-2">
{/* 文章标题 */}
<div className="flex items-center gap-1.5 text-xs">
@@ -137,7 +138,7 @@ export function OutlineCard({ outline, onChange, readOnly = false }: OutlineCard
</Button>
)}
</div>
)}
</CollapseTransition>
</div>
);
}
@@ -1,7 +1,8 @@
import { useState } from 'react';
import { ChevronRight, ChevronDown, Plus, X, GripVertical } from 'lucide-react';
import { ChevronRight, Plus, X, GripVertical } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { OutlineSection as OutlineSectionType } from '../../types/ai-writing';
import { CollapseTransition } from './CollapseTransition';
interface OutlineSectionProps {
section: OutlineSectionType;
@@ -72,9 +73,12 @@ export function OutlineSection({
onClick={() => setExpanded((v) => !v)}
className="shrink-0"
>
{expanded
? <ChevronDown className="size-3.5 text-muted-foreground" />
: <ChevronRight className="size-3.5 text-muted-foreground" />}
<ChevronRight
className={cn(
'size-3.5 text-muted-foreground transition-transform duration-200',
expanded && 'rotate-90',
)}
/>
</button>
<span className="text-muted-foreground/60 shrink-0 w-4 text-center">{index + 1}.</span>
@@ -109,7 +113,7 @@ export function OutlineSection({
</div>
{/* 要点列表 */}
{expanded && (
<CollapseTransition open={expanded}>
<div className="px-8 pb-2.5 space-y-1 border-t">
{section.keyPoints.map((kp, i) => (
<div key={i} className="flex items-center gap-1.5 pt-1.5">
@@ -142,7 +146,7 @@ export function OutlineSection({
</button>
)}
</div>
)}
</CollapseTransition>
</div>
);
}